前面我写了一篇关于 Minor Gc 的文章,看得人虽然不多,但是很多人的评论给我留下了深刻的印象。今天我们继续进步,学习一下 Major Gc。
关于 Major Gc,很少有书籍或者文章来单独写它。大多数都是把它和 Minor Gc、Full Gc 放在一起来写,Major Gc 基本上是一笔带过。
参考国外的一些文章,Major Gc 主要是用来回收老年代的。现在的 Gc 基本上都是采用分代回收的,包括 G1 的按区域回收,其实也是分代思想。年轻代由 Minor Gc 进行回收,采用复制算法。Major Gc 主要回收老年代区域,采用标记清除算法。Full Gc 回收整个堆。
MinorGC(次要的) 发生回收的时候,往往也可以伴随着 MajorGC 的发生。因为,这时有些对象会被移动到老年代中,当老年代的空间不够了,就可能发生 MajorGC(重要的) 。MajorGC 速度比 Minor GC 慢 10 倍以上。
MajorGC 在发生时,一般采用两次标记。一个对象被真正判定为“死亡”,需要进行两次标记(被标记为可回收对象),然后在下一次 JVM 进行 GC 的时候,才被真正的回收掉。如果一个对象没有与 GC Roots 的引用链相连接,也并没有被真正判定为“死亡”,而是进行第一次标记,然后在第二次标记之前会进行“自救”过程。所谓的“自救”就是在第二次被标记之前,需要重新与引用链相连接。在第一次被标记后,对象会进行筛选,筛选的条件为是否有必要进行执行 finalize() 方法。如果没有必要执行 finalize() 方法,则就等待第二次被标记;如果有必要执行 finalize() 方法,则会先将对象放置在一个叫 F-Queue 的队列中,然后等待虚拟机通过Finalizer线程去触发对象的 finalize() 方法,然后在 finalize() 方法里面,对象就开始自救的过程。对象自救可以通过把this赋值给某个类变量或者对象的成员变量,就实现了和引用链重新连接的目的——自救成功。因此在第二次标记的时候就会把对象从 F-Queue 队列中移除,然后虚拟机会在 F-Queue 中进行第二次小规模的标记,然后就等待下一次 GC 的来临。
“标记-清除”算法是最基础的收集算法。算法分为”标记”和”清除”两个阶段。
标记出所有需要回收的对象(遍历堆标记);标记完成后统一回收所有被标记的对象(遍历堆删除);”标记-清除”算法的不足之处。
“标记-清除”算法由两个问题,大家需要记住。
- 效率问题:标记 和 清除这两个过程效率都不高。
- 空间问题:标记和清除后会产生大量 不连续的 内存碎片,空间碎片太多 可能会导致 以后在程序运行中 需要分配较大对象时,无法找到足够连续内存而不得不触发一次垃圾回收,触发一次之后要是内存还不够,就会连续触发,导致OOM
老年代的垃圾收集叫做 Major GC。
Minor GC 和 Major GC 其实就是年轻代 GC 和年老年 GC 的俗称。而在 Hotspot VM 具体实现的收集器:Serial GC, Parallel GC, CMS, G1 GC中,大致可以对应到某个 Young GC 和 Old GC 算法组合。
更多面试题,请关注我的个人小程序。
: » 面试必问的 Major Gc 你了解一下
原创文章,作者:sunnyman218,如若转载,请注明出处:https://blog.ytso.com/252095.html