首页 > 编程知识 正文

jvm垃圾回收器和垃圾回收算法,jvm垃圾回收算法和垃圾回收器

时间:2023-05-05 14:59:15 阅读:190105 作者:1050

在前面的介绍中,明确了JVM的对象是如何判断生存和垃圾回收算法的。 垃圾回收的算法是怎么实现的呢? 由于HotSpot虚拟机在重用对象时对运行效率的要求非常苛刻,因此只有这样才能保证虚拟机的高效运行。

我们知道垃圾回收的算法枚举根节点可达性分析算法需要GC Roots对象,GR Roots对象的构成有这4种。

由类型1的虚拟机堆栈(局部变量表)引用的对象2方法区域内的类静态属性引用的对象3方法区域内的常数引用的对象4本地方法堆栈内的JNI ) (通常称为Native方法)

上图简要介绍了GC Roots对象的配置。 如果知道了这个,就回到垃圾回收的问题吧。 在许多APP应用程序中,仅方法区域就有几百MB。 如果一个一个地检查引用的话,会非常花时间。 另外,列举GC Roots节点时,程序中需要停顿【Stop The World】(因为分析中对象的参照关系不能不断变化,这是保证分析结果正确性的基础。 )所以,我不能花很多时间扫描方法区域,但是虚拟机如何才能在不扫描方法区域的情况下找到可以用作GC Roots的对象呢?

HotSpot实现使用一组称为OopMap的数据结构来实现这一点。 类加载完成后,HotSpot会计算对象中的哪个偏移包含什么类型的数据,并在JIT编译(即时编译器)期间将堆栈和寄存器中的哪个位置作为引用记录在特定位置。 通过这种方式,GC可以在扫描时直接从OopMap中获得GC Roots的对象。 你不需要一个人一个人找。 (用空间改变时间)

安全方面,我们知道在OopMap的帮助下,可以迅速完成GC根的枚举。 这样一来,有可能导致参照关系变化和OopMap内容变化的指令非常多,如果针对每个指令生成对应的OopMap,则需要大量的额外空间,存在GC的空间成本变高的问题。 虚拟机如何解决这个问题呢?

实际上,HotSpot只在“特定位置”记录这些信息,而不是为每个命令生成OopMap。 这些位置称为“安全点”(Safepoint )。 也就是说,程序运行中并不是所有的地方都可以停止并开始GC,只有在到达安全点时才能暂停。 选择Safepoint时,请不要让GC的等待时间过长,也不要频繁地让运行时的负荷过大。 因此,安全点的选定基本上是以程序是否具有长时间执行程序的特征为基准来选定的。 ——由于每个命令执行的时间非常短,所以以指令流的长度过长为理由长时间执行程序的可能性很低。 长时间执行最明显的特点是方法调用、循环跳转、异常跳转等指令序列的复用,所以具有这些功能的指令生成Safepoint。

对于Sefepoint,另一个需要考虑的问题是,发生GC时,所有线程(在本例中为执行JNI调用的线程除外)都必须“跑到”最近的安全点,然后停止。 这里有两个选择。

中断方式为先占中断(Preemptive Suspension )先占中断不需要线程的执行代码积极协作,发生GC时首先中断所有线程,如果线程中断的位置不在安全点,则重新启动线程目前,几乎没有实现通过先行中断中断线程、响应GC事件主动中断的虚拟机。 GC需要中断线程时,不直接对线程操作,而只设置标志,各线程执行时自行轮询该标志,发现中断标志为真时自行中断并中断。 除了轮询标志的位置和安全点重叠外,通过在为了创建对象而需要分配内存的位置安全区Safepoint机制,可以缩短程序运行时遇到可以访问GC的Safepoint的时间但是,如果程序“不运行”,如线程处于休眠或阻塞状态,则线程将无法响应来自JVM的中断请求,并前往安全的地方中断挂起。 在这种情况下,需要在安全区域(Safe Region )解决。

安全区域是指在代码片段中引用关系不变。 从这个区域的任何地方开始GC都是安全的。 也可以将“Safe Region”视为扩展的“Safepoint”。

当线程运行到Safe Region代码时,它首先标识自己进入了Safe Region。 这样,在此期间,当JVM尝试启动GC时,就不再需要将其标识为处于安全注册状态的线程。 当线程离开Safe Region时,请检查系统是否完成了根节点枚举(或整个GC进程),如果完成,则继续执行该线程。 如果没有完成,必须等到收到可以安全离开Safe Region的信号。

参照《深入理解Java虚拟机》

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。