JVM 关键点详解

news2024/9/22 19:40:26

一,JVM 的主要组成部分及其作用

JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执行引擎); 两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。

Class loader(类装载): 根据给定的全限定名类名(如: java.lang.Object)来装载class文件到Runtime data area中的method area。

Execution engine (执行引擎) : 执行classes中的指令。

Native Interface(本地接口): 与native libraries交互,是其它编程语言交互的接口。

Runtime data area(运行时数据区域): 这就是我们常说的JVM的内存。作用: 首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区 (Runtime data area) 的方法区内,而字节码文件只是JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎 (Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口 (Native lnterface)来实现整个程序的功能。

下面是Java程序运行机制详细说明

Java程序运行机制步骤

首先利用IDE集成开发工具编写Java源代码,源文件的后缀为.java;再利用编译器(javac命令)将源代码编译成字节码文件,字节码文件的后缀名为.class;运行字节码的工作是由解释器(java命令)来完成的。

从上图可以看,java文件通过编译器变成了.class文件,接下来类加载器又将这些,.class文件加载到JVM中。其实可以一句话来解释:类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class对象,用来封装类在方法区内的数据结构。

二,堆栈的区别

官方文档中有这么一句话

翻译成中文就是:java 虚拟机是一种抽象的计算机。

既然是计算机就需要遵循冯诺依曼的计算机体系模型。

类加载器相当于输入设备,执行引擎相当于输出设备,堆和方法区相当于存储器,栈相当于中央处理器。

 物理地址角度

堆的物理地址分配对对象是不连续的。因此性能慢些。

在GC的时候也要考虑到不连续的分配,所以有各种算法。比如,标记-消除,标记-复制,标记-压缩,分代 (即新生代使用标记-复制算法,老年代使用标记-压缩)

栈使用的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快。

内存角度

堆因为是不连续的,所以分配的内存是在运行期确认的,因此大小不固定。一般堆大小远远大于栈。

栈是连续的,所以分配的内存大小要在编译期就确认,大小是固定的。

存放的内容角度

堆存放的是对象的实例和数组。因此该区更关注的是数据的存储。

栈存放:局部变量,操作数栈,返回结果。该区更关注的是程序方法的执行。

程序的可见度角度

堆对于整个应用程序都是共享、可见的。

栈只对于线程是可见的。所以也是线程私有,他的生命周期和线程相同,

三,JVM类加载机制的特性

  • 全盘负责

当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。

例如,系统类加些器AppClassLoader加想入口类 (含有main方法的类)时,会把main方法所依赖的类及引用的类也载入,依此类推。“全盘负责”机制也可称为当前类加载器负责机制。显然,入口类所依赖的类及引用的类的当前类加裁器就是入口类加载器。

以上步要只是调用了ClassLoaderloadClass(name)方法,并没有真正定义类,真正加载class字节码文件牛成Class对象由“双亲委派”机制完成。

  • 父类委托

“双亲委派”是指子类加载器如果没有加载过该目标类,就先委托父类加载咒加载该目标类,只有在父类加载器找不到字节码文件的情况下才从自己的类路径中查找并装载目标类。

父类委托别名就叫双亲委派机制。“双亲委派”机制加载Class的具体过程是

1.ClassLoader先判断该Class是否已加载,如果已加载,则返回Class对象;如果没有则委托给父类加载器,

2. 父类加载器判断是否加载过该Class,如果已加载,则这回Class对象,如果没有则委托给祖父类加载器。

3.依此类推,直到始祖类加载器 (引用类加载器)。

4. 始祖类加载器判断是否加载过该Class,如果已加载,则返回Class对象;如果没有则尝试从其对应的类

三,对象的生命周期

1,创建阶段

(1)为对象分配存储空间
(2)开始构造对象
(3)从超类到子类对static成员进行初始化
(4)超类成员变量按顺序初始化,递归调用超类的构造方法
(5)子类成员变量按顺序初始化,子类构造方法调用,并且一旦对象被创建,并被分派给某些变量赋值,这个对象的状态就切换到了应用阶段

2,应用阶段

(1)系统至少维护着对象的一个强引用(Strong Reference)
(2)所有对该对象的引用全部是强引用(除非我们显式地使用了:软引用(Soft Reference)、
	弱引用(Weak Reference)或虚引用(Phantom Reference))

引用的定义:
1.我们的数据类型必须是引用类型
2.我们这个类型的数据所存储的数据必须是另外一块内存的起始地址

3,不可见阶段

不可见阶段的对象在虚拟机的对象根引用集合中再也找不到直接或者间接的强引用,最常见的就是线程或者函数中的临时变量。程序不再持有对象的强引用。(但是某些类的静态变量或者JNI是有可能持有的 )

4,不可达阶段

指对象不再被任何强引用持有,GC发现该对象已经不可达

与不可见阶段的区别就是:不可达是经过算法之后的
那么有哪些算法?

引用计数:
	对象有一个引用就+1,去掉一个引用就-1,当引用数为0就认为是没有引用,可以回收
	问题:解决不了循环依赖问题

在这里插入图片描述

可达性分析:通过GC Root的对象,开始向下寻找,看某个对象是否可达什么能看作GC ROOT:加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法栈的变量等本质上就是一组活跃的引用

在这里插入图片描述

5,收集阶段

看对象需不需要执行finalize方法:
如果不需要:虚拟机已经调用过finalize方法或者对象没有重写finalize方法,那么对象可以回收
需要:虚拟机将对象放入F-queue,创建一个低优先级的线程执行队列中对象的finalize方法finalize方法中是否重新为该对象建立引用连接
是:虚拟机将对象移出F-queue队列,对象重新回到应用阶段
否:对象可以回收

finalize方法会影响JVM的对象以及分配回收速度
finalize方法可能会让对象复活

6,终结阶段

对象的finalize()函数执行完成后,对象仍处于不可达状态,该对象进程终结阶段。

finalize方法代码Demo:

package com.mugua.platform;

class FinalizeEscapeGC {

    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("yes, i am still alive;");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize method executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable {
        SAVE_HOOK = new FinalizeEscapeGC();

        SAVE_HOOK = null;
        System.gc();
        Thread.sleep(500);
        if (SAVE_HOOK == null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no, i am dead :(");
        }

        SAVE_HOOK = null;
        System.gc();
        Thread.sleep(500);
        if (SAVE_HOOK == null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no, i am dead :(");
        }
    }
}

第一次成功通过finalize方法成功逃脱回收名单,但第二次因为finalize方法之前已经被调用过,因此不会在执行finalize方法,所以注定被回收了。

注意:finalizer线程执行每个对象的finalize方法时是非阻塞的,因此并不保证GC进行第二次标记时finalize方法执行完成。

7,对象内存空间重新分配阶段

GC对该对象占用的内存空间进行回收或者再分配,该对象彻底消失

四,对象模型对齐填充

64位的操作系统寻址空间2的64次方每次读取64个二进制,也就是8字节

对齐填充的意义是 提高CPU访问数据的效率,主要针对会存在该实例对象数据跨内存地址区域存储的情况.例如: 在没有对齐填充的情况下,内存地址存放情况如下:

 因为处理器只能0x00-0x07,0x08-0x0F这样读取数据,所以当我们想获取这个long型的数据时,处理器必须要读两次内存,第一次(0x00-0x07),第二次(0x08-0x0F),然后将两次的结果才能获得真正的数值。

那么在有对齐填充的情况下,内存地址存放情况是这样的:

现在处理器只需要直接一次读取(0x08-0x0F)的内存地址就可以获得我们想要的数据了。

四,对象的创建过程 

般情况下,新创建的对象都会被分配到Eden区,一些特殊的大的对象会直接分配到Old区。

W我是一个普通的Java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“From”区,自从去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定所,直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的。

五,为什么需要两个Survivor区?

最大的好处就是解决了碎片化。也就是说为什么一个Survivor区不行?第一部分中,我们知道了必须设置Survivor区。假设现在只有一个Survivor区,我们来模拟一下流程:刚刚新建的对象在Eden中一旦Eden满了,触发一次Minor GCEden中的存活对象就会被移动到Survivor区,这样继续循环下去下一次Eden满了的时候,问题来了,此时进行Minor GCEden和Survivor各有一些存活对象如果此时把Eden区的存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化。永远有一个Survivor space是空的,另一个非空的Survivor space无碎片。

六,堆内存中都是线程共享的区域吗

JVM默认为每个线程在Eden上开辟一个bufer区域,用来加速对象的分配,称之为TLAB,全称:Thread LocalAllocation Buffer。
对象优先会在TLAB上分配,但是TLAB空间通常会比较小,如果对象比较大,那么还是在共享区域分配。

七,方法区与元数据区以及持久代到底是什么关系

八,栈帧结构

 动态链接是为了支持方法的动态调用过程。

动态链接将这些符号方法引用转换为具体的方法引用。

为了支持java的终态符号引用转变为直接引用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/453064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux网络】部署YUM仓库及NFS服务

部署YUM仓库及NSF服务 一、YUM仓库1.1、YUM仓库概述1.2准备安装来源1.3在软件仓库加载非官方RPM包组1.4yum与apt 二、配置yam源与制作索引表2.1配置FTP源2.2配置国内在线yum源2.3在线源与本地源同时使用2.4建立软件包索引关系表的三种方法 三、nfs共享存储服务3.1安装软件&…

LVS负载均衡群集——NAT模式实操

1.1 群集的的定义及意义 群集的定义 Cluster,集群(也称群集)由多台主机构成,但对外只表现为一一个整体,只提供一-个访问入口(域名或IP地址), 相当于一台大型计算机。 群集的作用 对于企业服务的的性能提升…

数学知识四

容斥原理 S表示面积,下面公式可求出不相交的面积 2个圆的公式是这样 4个圆的面积是 总面积-所有俩俩相交的面积所有三三相交的面积-四四相交的面积,公式里加和减互相出现。 从n个集合里面挑一个一直到从n个集合里面挑n个 1-10中,能被2&#x…

【KingSCADA】如何创建新应用

大家好,我是雷工! 今天学习使用KingSCADA3.8创建一个新的应用,以下为学习过程和操作笔记。 一、前言 KingSCADA3.8集成开发环境是基于工程的应用管理模式,实现了对多个应用的集中开发和管理的功能,一个工程可以同时管理多个应用…

【WinForm】Android手机群控工具-桌面程序开发实现

如何将手下多个Android手机统一管理起来呢,这里是用通过终端输入adb命令来实现控制多个手机的,具体怎么做,接下来给讲一讲。 使用adb工具包 首先,需要准备一套工具,以下是adb工具套件,是在Android SDK开发…

lanuage-driven semantic segmentation

CLIP 改进工作串讲(上)【论文精读42】_哔哩哔哩_bilibili更多论文:https://github.com/mli/paper-reading, 视频播放量 64310、弹幕量 274、点赞数 1939、投硬币枚数 1332、收藏人数 821、转发人数 438, 视频作者 跟李沐学AI, 作者简介 &…

window安装cplex20.1.0启动报错: ilog.odms.ide.opllang.IloOplLangPlugin

通过0-1背包问题看穷举法、贪心算法、启发式算法(JAVA) 模拟退火(SA)算法实例介绍(JAVA) 遗传算法(GA)实例介绍(JAVA) CPLEX求解器入门案例 java集成Cplex:Cplex下载、IDEA环境搭建、docker部署 windo…

线性链表 反转 -(递归与非递归算法)_20230420

线性链表 反转 -(递归与非递归算法)_20230420 前言 线性链表反转是非常有趣的算法,它可以采用多种方式实现,比较简洁的方法是递归反转;传统的方式是利用迭代反转,设定三个变量,采用类似滚动数组的方式,实…

React Hooks生命周期

文章目录 前言一、类组件的生命周期1、什么是类组件2、生命周期钩子 二、函数组件生命周期1、什么是函数组件2、模拟类组件生命周期钩子 三、为什么要使用生命周期1、我们能在钩子里面干什么2、PureComponent和React.memo区别 总结 前言 最近在写react项目,所以一直…

【Java网络编程】Socket套接字

哈喽,大家好~我是你们的老朋友: 保护小周ღ,本期为大家带来的是网络编程的前提概念 Socket 套接字,操作系统提供Socket 用于封装底层的协议细节和通信逻辑,使应用程序可以通过简单直观的API与网络进行交互。所以客观的…

在poetry虚拟环境下打包exe

本博客介绍了在poetry虚拟环境下打包exe的流程,包含两个部分 打包的基本流程打包过程中遇到的问题 打包的基本流程 copy打包工具到本地,(share:\公用共享\芯片部\乔羽\img_generate\系统部提供的打包exe工具) 用poetry搭建虚拟环境 在打包…

微积分入门

文章目录 前言初期积分微分微积分问题 后期极限 ε \varepsilon ε- δ \delta δ极限勒贝格积分 结语 前言 微积分总共走过了两个时期。首先是牛顿和莱布尼茨利用无穷小量定义微分和积分,并且发现了微分和积分的关系,这是第一个时期,这时的…

如何在元宇宙中促进品牌增长:消费者喜好的热点调查

欢迎来到Hubbleverse 🌍 关注我们 关注宇宙新鲜事 📌 预计阅读时长:5分钟 本文仅代表作者个人观点,不代表平台意见,不构成投资建议。 音乐和旅游是用户被元宇宙虚拟体验所吸引的前两个领域。根据Reach 3 Insights的…

ArrayList 的特点及优缺点

前面讲过,数组有很多缺点且使用不太方便,但是我们存储数据的时候很多情况又不得不使用它,那么有没有对数组封装一下的类,让我们更方便呢?答案是有的,他就是 ArrayList,他是一个基于数组的集合&a…

Ceph入门到精通- storcli安装

storcli 是LSI公司官方提供的Raid卡管理工具,storcli已经基本代替了megacli,是一款比较简单易用的小工具。将命令写成一个个的小脚本,会将使用变得更方便。 安装简单,Windows系统下解压出来以后可以直接运行。 Linux系统默认位置…

CGI, FastCGI, WSGI, uWSGI, uwsgi一文搞懂

1. CGI # 1、通用网关接口(Common Gateway Interface/CGI)是一种重要的互联网技术,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI描述了服务器和请求处理程序之间传输数据的一种标准。 # 2、CGI程序可以…

今儿咱就看看redis的淘汰策略你知道多少

一、前言 Redis在我们日常开发中是经常用到的,Redis也是功能非常强大,可以进行缓存,还会有一些排行榜、点赞、消息队列、购物车等等;当然还有分布式锁Redisson,我们使用肯定少不了集群!小编最近学习到一些…

AI-ISP:手机相机是如何将风景变成图片的?

文章目录 前言1. ISP芯片2. Sensor知识3. RAW数据4. ISP Pipeline5. AI-ISP结束语 前言 本篇文章只干一件事:AI-ISP:手机相机是如何将风景变成图片的? 1. ISP芯片 一颗小小的SoC芯片(10mm x 10mm)上集成了一百多亿个晶体管(Kirin 9000有153亿…

【pandas】Python读取DataFrame的某行或某列

行索引、列索引、loc和iloc import pandas as pd import numpy as np # 准备数据 df pd.DataFrame(np.arange(12).reshape(3,4),indexlist("abc"),columnslist("WXYZ"))行索引(index):对应最左边那一竖列 列索引(columns):对应最…

建筑数据破解JS逆向爬虫

建筑数据破解JS逆向爬虫 地址:https://jzsc.mohurd.gov.cn/data/project GitHub地址:https://github.com/NearHuiwen/JzscCrawler RequestsPyExecJS JS文件:req_aes.js 目标 抓包,抓取建筑市场数据(注:用于学习&am…