老年代具体又是怎么进行垃圾回收的呢?
这个过程说起来可能稍微复杂了一点,但是它和CMS的垃圾回收过程其实是类似的。关于CMS的垃圾回收的几个阶段可以回顾王子的上篇文章探索ParNew和CMS垃圾回收器。
首先我们要弄明白,什么时候会触发新生代和老年代的混合垃圾回收?
G1有一个参数“-XX:InitiatingHeapOccupancyPercent”,默认值为45%。
什么意思呢?就是说当老年代占据了堆内存的45%的Regionf的时候,就会触发混合垃圾回收。
具体流程是什么样的呢?
首先会触发一次初始标记操作,这个过程是要“Stop the World”的,对应的就是CMS的初始标记阶段,细节不再说明。
接着会进入并发标记阶段,这个阶段同样对应CMS的并发标记阶段,不再说明。
接着会进入最终标记阶段,这个阶段其实和CMS的重新标记阶段也基本一致。
最后就是混合回收阶段,这个阶段和CMS的并发清理阶段就不太一样了,这个阶段会计算每个Region中的存活对象数量,存活数量占比,还有执行垃圾回收的耗时等问题。
接着会进入“Stop the World”阶段,然后全力以赴进行垃圾回收,并尽量保证停止时间不超过我们设定好的时间,所以可能只会回收掉之前标记好的一部分垃圾对象。
为什么要叫做混合回收呢,因为它不仅仅回收的是老年代,新生代和大对象的Region也会同时进行回收,而具体回收哪些Region就要视情况而定了,根据价值回收价值G1会自己做出选择。
而混合回收是可以进行多次的,比如先停止系统,混合回收掉一部分Region,再停止系统,再执行一次混合回收。
有参数可以控制这个数量,“-XX:G1MixedGCCountTarget”参数,就是在一次混合回收的过程中,最后一个阶段执行几次,默认是8次。
为什么要这样反复多次的回收呢?
因为这样每次回收停止系统的时间都很短,在回收的间隙系统是可以正常运行的。
还有个参数“-XX:G1HeapWastePercent”,默认值是5%。
它的意思是,混合回收的时候,都是基于复制算法进行的,把Region存活的对象放入其他Region,然后清除掉本来的Region。那么当空闲的Region数量达到堆内存的5%,就会立即停止混合回收。
而通过这种复制算法回收,也不会出现像CMS标记清理算法导致的内存碎片问题。
还有个参数“-XX:G1MixedGCLiveThresholdPercent”,默认值是85%,意思就是回收Region的时候,存活的对象必须少于85%才可以被回收掉。否则存活对象太多,复制的时候成本是很高的。
如果回收失败怎么办?
如果在复制的时候发现没有空闲的Region可以承载存活的对象,那么会触发失败,立马停止系统进程,采用单线程进行标记、清理和压缩整理,空闲出一批Region,这个过程是极慢的。
总结
本文我们对G1的内存机制和垃圾回收的算法做了一个比较清晰的解释。
阅读完本文,相信小伙伴们自己可以总结出G1和CMS究竟有什么不一样了吧。
欢迎小伙伴们留言区讨论G1和CMS的区别,王子会第一时间回复。
那我们下篇文章再见。
往期文章推荐:
大白话谈JVM的类加载机制
JVM内存模型不再是秘密
轻松理解JVM的分代模型
秒懂JVM的垃圾回收机制
探索ParNew和CMS垃圾回收器