GC算法

旧城等待, 2021-11-09 16:22 381阅读 0赞

GC算法:
标记-清除(Mark-Sweep)算法,算法分为“标记”和“清除”两个阶段:
首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象,它的标记过程其实在前一节讲述对象标记判定时已经介绍过了。之所以说它
是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其不足进行改进而得到的。
不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程
序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

复制(Copying)算法出现了,为了解决效率问题,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半,未免太高了一点。

HotSpot虚拟机默认Eden和Survivor的大小比例是8:1.
当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion)。如果另外一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象时,
这些对象将直接通过分配担保机制进入老年代。关于对新生代进行分配担保的内容,在本章稍后在讲解垃圾收集器执行规则时还会再详细讲解。

标记-整理算法
老年代的特点,“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存.

商业虚拟机的垃圾收集都采用“分代收集”(Generational Collection)算法,根据对象存活周期的不同将内存划分为几块.
一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法.

HotSpot的算法
1.枚举根节点
GC Roots的在很多应用仅仅方法区就有数百兆,如果要逐个检查这里面的引用,那么必然会消耗很多时间,
GC进行时必须停顿所有Java执行线程,Stop The World,可以理解为加了锁,以必要的停顿用来枚举根节点.

主流Java虚拟机都是准确式GC,STW并不需要逐个检查所有执行上下文和全局的引用位置,虚拟机应当是有办法直接得知哪些地方存放着对象引用。
HotSpot是使用一组称为OopMap的数据结构,在类加载完成的时候就把对象内什么偏移量上是什么类型的数据计算出来.
在JIT编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用.
这样GC在扫描时就可以直接得知这些信息了.

2.安全点
如果为每一条指令都生成对应的OopMap,那将会需要大量的额外空间,这样GC的OopMap空间成本将会变得很高。
程序执行时并非在所有地方都能停顿下来开始GC,在“特定的位置”记录了这些信息,这些位置称为安全点(Safepoint),即只有在到达安全点时才能暂停。
Safepoint的选定既不能太少以致于让GC等待时间太长,也不能过于频繁以致于过分增大运行时的负荷。

安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定的
因为每条指令执行的时间都非常短暂,程序不太可能因为指令流长度太长这个原因而过长时间运行.
“长时间执行”的最明显特征就是指令序列复用,例如方法调用、循环跳转、异常跳转等,所以具有这些功能的指令才会产生Safepoint。
对于Sefepoint,另一个需要考虑的问题是如何在GC发生时让所有线程(这里不包括执行JNI调用的线程)都“跑”到最近的安全点上再停顿下来。
这里有两种方案可供选择:抢先式中断(Preemptive Suspension)和主动式中断(VoluntarySuspension).
其中抢先式中断不需要线程的执行代码主动去配合,在GC发生时,首先把所有线程全部中断,如果发现有线程中断的地方不在安全点上,就恢复线程,让它“跑”到安全点上。现在几乎没有虚拟机实现采用抢先式中断来暂停线程从而响应GC事件。
而主动式中断的思想是当GC需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起.轮询标志的地方和安全点是重合的,另外再加上创建对象需要分配内存的地方。

3.安全区域

垃圾回收器:

发表评论

表情:
评论列表 (有 0 条评论,381人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JVM GC算法:复制算法

    > 为了解决标记-清除算法的效率不高的问题,产生了复制算法。它把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾收集时,遍历当前使用的区域,把存活对象复制到另外一个区域

    相关 GC算法GC收集器

    Java相比于C++这样语言,除了跨平台的特性外,最突出的特点就是垃圾回收机制。C++的开发人员还需要手动分配和回收内存,但JVM直接承担起了垃圾回收的重任,开发人员可以专注于

    相关 GC算法实现

    在了解了上一章中GC算法的基本概念之后,本章将深入到各GC算法的具体实现中。对大多数JVM来说,一般需要选择两种GC算法,一种用于回收新生代内存区,另一种用于回收老年代内存区域

    相关 JVM GC系列 — GC算法

    一.前言 从本篇文章开始,将开始一个新的系列JVM。JVM是一个非常庞大且复制的技术体系,但是对于程序猿的升级,走向更高阶所必要经历的,曾经也下决心要好好学习一番,然而毅

    相关 GC算法

    GC算法: 标记-清除(Mark-Sweep)算法,算法分为“标记”和“清除”两个阶段: 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象,它的标记过