jvm
2022-03-16 21:39:23 78 举报
Java虚拟机(JVM)是运行所有Java程序的虚拟计算机。它是Java技术的核心,具有平台独立性的特点,即Java编写的程序(编译后的字节码)可以在任何装有JVM的平台上运行,无需重新编译。 JVM在执行Java程序时,会将字节码翻译成具体平台的机器指令执行,从而实现了Java语言的“一次编写,到处运行”。此外,JVM还提供了内存管理、垃圾回收等功能,使得开发者无需关心底层硬件和操作系统的细节,可以专注于编写程序的逻辑。总的来说,JVM是Java语言的重要基础,它使得Java具有了跨平台的特性,并且简化了Java程序的开发和部署。
作者其他创作
大纲/内容
YoungGC
虚拟机不使用引用计数算法:根据对象引用进行计数,当引用为0时,对象意味着没有任何使用,则可以视为垃圾
方法区
自定义类加载器
2.如果Java堆内存是不规整的也就是杂乱无章的,Java虚拟机就必须创建一个列表来记录那些空闲内存的位置,当要为对象分配一个新的内存空间时,就在列表中找到对应大小位置的内存地址,划分给对象,这种方法叫做“空闲列表”
卡表元素变脏-其他分代区域中对象引用了本区域对象时。如何在卡表元素变脏,即对象赋值的那一刻去更新维护卡表状态?写屏障技术维护卡表状态。写屏障可以看做在虚拟机层面对“引用类型字段赋值”这个动作的AOP切面,在引用对象赋值时会产生一个环形通知,供程序执行额外的动作,也就是说赋值的前后都在写屏障的覆盖范围内。
垃圾回收算法机制
除了划分空间之外,对象创建在虚拟机是非常频繁的行为,并发的情况是线程不安全的。解决方案一种是对分配内存空间的动作进行同步处理---实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;另外一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),那个线程要分配内存,就在哪个线程的本地缓冲区中分配,只有本地缓冲区用完了,分配新的缓存区时才需要同步锁定。
程序不运行时:就是没有分配处理器时间,或者用户线程sleep和blocked状态,这时候线程无法响应虚拟机的中断请求。这种情况,就必须引入安全区域。安全区域:是指能够确保在某一段代码片段中,引用关系不会发生变化,因此,在这个区域中任意地方开始垃圾收集都是安全的。当用户线程执行到安全区域代码时,首先会标识自己已经进入安全区域,那这段时间虚拟机发起垃圾收集时不再用去管这些进入安全区域的线程。当这些线程离开安全区域时,它会检查虚拟机是否完成了根节点枚举,如果完成了,线程就当没事发生继续执行,如果没完成,它则必须在安全区域继续等待,直到收到可以离开安全区域的信号为止
操作数栈
当发生垃圾收集时,如何让线程都跑到最近安全点,然后停顿下来等待被收集?1.抢先式中断:垃圾收集发生时,系统首先把所有用户线程全部中断,如果发现有用户线程不再安全点上,就恢复这条线程执行,让他一会中断,直到跑到安全点2.主动式中断:不直接对线程操作,设置标志位,各个线程执行时主动去轮询这个标志,发现中断标志为真时,就在自己最近安全点上主动挂起。
并发的可达性分析:可达性分析算法理论上要求全过程基于一个能保障一致性的快照中才能够进行分析,也就是stop the world。GC Roots已经在各种优化下,所造成的stw已经很短了,不再随堆容量而增长了。可视GC Roots继续往下遍历对象图,就与Java堆容量成正比关系了。“标记”是所有追踪式垃圾手机算法的共同特征,并发可达性分析,就是为了减少标记时造成的stw。所谓的并发标记也就是用户线程和垃圾收集线程同时工作。可是并发标记会导致产生浮动垃圾和“对象消失”的问题浮动垃圾问题是不会影响程序运行的。针对于“对象消失”,我们知道当且仅当以下两个条件同时满足时,才会发生:1.赋值器插入了一条或多条从黑色对象到白色对象的新引用2.赋值器删除了全部从灰色对象到该白色对象的直接引用或间接引用解决方案:增量更新和原始快照(SATB)增量更新:当黑色对象插入新的指向白色对象的引用关系时,将这个新插入的引用记录下来,等并发扫描结束后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。简化理解:黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象了。原始快照:当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束后,再将这些记录过的引用关系中的灰色对象为根,重新扫描一次。简化理解:无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来进行搜索
标记-复制
Java虚拟机还要对对象进行必要的设置,根据对象头获取获取对象与之对应的类。以上操作完成后,从虚拟机角度来看,一个新的对象已经产生了。但是从Java程序的视角来看,对象创建才刚刚开始--构造函数,即Class文件中的<init>()方法还没有执行,所有的字段都默认的零值。new指令之后才会接着执行<init>()方法,这样一个真正可用的对象才算完全被构造出来。
动态连接
类加载器
应用类加载器(Application classloader)
Survivor1To
根节点枚举:由于Java程序越做越大,导致Java对象也会越来越多,方法区也会越来越大,根据可达性分析算法获取GC Roots的大小也会相应变大,但是有一部分的GC Roots是不会被用到的,虚拟机还是全局扫描所有的GC Roots的话,Stop the World的时间会很长,HotSpot的解决方案就是,使用一个OopMap的数据结构来达到这个目的(不再用全局扫描所有的GC Roots了)。一旦类的加载动作完成后,HotSpot就会把对象内什么偏移量上什么类型的数据记录下来,在即时编译过程中,也会在特定位置中记录栈里和寄存器哪些是位置引用。这样垃圾收集器就不用全部扫描了。
准备
启动类加载器(bootstrap classLoader)
加载:1.通过一个类的全限定名来获取定义此类的二进制字节流 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据 3.在内存中生成一个代表这个类的java.lang.Class对象。作为方法区这个的各种数据的访问入口验证:文件格式验证、元数据验证、字节码验证和符号引用验证 准备:准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段 解析:解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程。初始化:初始化阶段就是执行类构造器方法<clinit>()的过程
初始化
HotSpot虚拟机创建对象
线程共享;存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据
标记清除整理算法对应老年代
Survivor0From
栈帧:一个栈帧代表一个方法执行,入栈/出栈;线程私有
线程私有线程来回切换时,记录指令执行位置
标记-整理
如何维护卡表状态
线程私有;native方法
class files
验证
YoungGC:OldGC=1:2
连接
本地方法栈
解析
堆
程序运行时:由于导致OopMap内容变化的指令非常多,不可能全部记录下来,会需要非常大的空间,所以需要在特定的位置进行记录,我们称特定的 位置为安全点,只有在安全点位置才能进行GC(垃圾回收)
Eden:survivor0:survivor1=8:1:1
加载过程
线程共享;对象属性实际存放位置
标记-复制算法:将内存分为两块,每次只使用其中的一块,当这块使用完后,将所有存活的对象移动到另一块上,并把这块内存全部清除
程序计数器
类加载过程详情
1.如果Java堆内存是规整的,也就是正在使用的放置一旁,没用过的放置一旁,当分配新的内存时,就相当于有一个指针往空闲内存移动相对应的大小,这种就叫做“指针碰撞”。
Eden
标记-整理算法:标记所有存活的对象,标记结束后,将所有存活的对象往一端移动,清理边界以外的内存
扩展类加载器(ExtensionclassLoader)
方法返回地址
标记-清除算法:标记所有需要回收的对象,等标记完成后,清除所有被标记的对象
双亲委派机制
虚拟机栈
加载
记忆集变形,卡表
标记-清除
简单来说就是虚拟机遇到new指令时,先查看指令的参数是否在常量池中能定位到一个类的符号引用,并检查这个符号引用代表的类是否已被加载、解析初始化过。没有,则执行相应的类加载过程,执行完毕后虚拟机开始为对象分配内存,分配内存要考虑并发问题,然后虚拟机对对象进行必要的设置。以上完成后,才从Class文件执行<init>()方法
卡表就是记忆集的一种具体实现,它定义了记忆集的记录精度、与堆内存的映射关系等。卡表最简单形式可以是一个字节数组,每一个元素对应着其标识的内存区域中一块特定大小的内存块,这个内存块被称作“卡页”。卡页的内存中通常不止一个对象,只要对象中存在跨代指针,那就将对应卡表数组元素的值标识为1,称这个元素变脏了,扫描时只要筛选卡表变脏的元素,就知道哪些内存块中包含跨代指针,就将他们加入GC Roots
存放基本数据类型,引用类型,静态变量
堆内存分配
java虚拟机遇到new指令时,先去常量池定位能否查到一个类的符号引用,并检查判断这个是否加载,解析,初始化过,如果没有,虚拟机将会为这个对象分配内存。分两种情况:
避免扫描所有GC Roots,但是还是存在跨代引用的问题,老年代引用新生代数据,但是老年代数据过多,又不是所有老年代对象都存在跨代引用的问题,新生代中建立了记忆集的数据结构用于记录跨代引用指针。记忆集的记录精度:1.字长精度:每个记录精确到一个机器字长,跨代指针2.对象精度:每个记录精确到一个对象,对象包含跨代指针3.卡精度:每个记录精确到一块内存区域,区域包含跨代指针
标记复制算法对应新生代
运行时数据区
对应类加载器
OldGC
局部变量表
0 条评论
下一页