GC系列终章
最近看了很多GC的内容,从GC算法到垃圾回收器再到jvm调优,今天做一个总结,每天整理,提升多多!
1.确定GC的对象(哪些对象已死?)
高中物理老师告诉我们,学习要直捣黄龙!所以本篇文章争取不多废话,把有用的东西都铺展开来说。
手段有二
- 引用计数法:对于一个对象来说,有一个引用指向它。计数器就加1,断开这个引用,计数器就减1。这样的方式同操作系统的文件系统中文件共享手段的硬链接类似,但是区别在于GC对象也是可以指向别的对象的,所以就会有循环引用的问题存在,这也是不使用它的一个原因。
- 可达性分析算法:首先,需要确定GC ROOT,那么问题来了,到底哪些对象可以确定为GC ROOT对象呢?
- GC ROOT:就是那些在当前引用下肯定不会被回收的对象,比如静态引用。而GC是在堆上发生的,而虚拟机栈、方法区、本地方法栈不归堆管理,所以选择 1. 虚拟机栈中引用的对象 2. 方法区中类静态属性引用的对象 3.方法区中常量引用的对象 4. 本地方法栈中JNI引用的对象。
- 关于可达性分析算法的第二个问题就是GC Root trancing是如何开始的,根据国内JVM某大牛的说法,GC ROOT Trancing就是从一个给定集合的根出发,按照引用关系遍历对象图,找出所有存活的对象,把剩下的对象认为是死亡的对象,他们所占的空间是可以被回收的空间。
- 经过一次GC Root Trancing后,没有和根关联起来的对象会第一次被标记,后面再GC的过程中还会进行第二次标记,即执行一次finalize方法,此时如果第一次被标记的对象又重新和某个根对象关联起来了,那么它仍然可以存活。
2.垃圾回收算法
对于垃圾回收算法,有标记-清除、复制算法、标记-整理三种。复制算法常常用在新生代、标记-整理算法和标记-清除算法常常用在老年代。
前段时间面试阿里被问到,为什么要分代收集?比如在新生代用复制算法、在老年代用标记-整理算法?
原因在于jvm根据各个年代的特点采用最适当的收集算法,新生代中的对象存活的少,每次Minor GC都会有大批量的对象死去,所以复制算法只用复制少量的对象就可以完成收集。而在老年代,一般都是存活很久的对象,而且没有额外的空间作担保,所以采用标记-整理和标记-清除算法。
3. 垃圾收集器
关于7种垃圾收集器,网上的优秀博客也有很多,在这里只会记录一些我之前困惑的问题。
server端和client端中的垃圾回收有什么区别?
server启动慢,启动后性能高,主要是堆的区间大小设的大,适合B/S系统上web系统。client启动快,启动后性能差,适合有交互多的GUI。
说说你知道的垃圾收集器、以及他们的特点作用的区域。

记忆思路:单线程/多线程,新生代/老年代,Parallel Scavenge(吞吐量),cms,G1,结合图,很容易记忆
说说CMS收集器
从这几个方面去说:收集过程、收集区域、收集算法、优点、缺点。
收集过程,周的书上对CMS的收集过程描述为4个阶段。
初始标记:stw、标记GC root能直接关联到的对象。这句话应该这样理解,理解为选择可以作为GC Root的对象,并装在GC Roots集合中,这叫做直接关联而非间接关联。
并发标记:GC Root Trancing过程,在垃圾回收算法中已经说过。这个过程虽然很慢,但是由于是并发,所以不需要STW。
并发预处理:理清这个阶段标记哪些对象,1.并发阶段被修改了的对象。2.从新生代晋升的对象。3.新分配到老年代的对象。这里就有一个问题存在,我们回收的是老年代,可是关联的对象有可能存在新生代,所以GC时会进行全堆扫描,效率低下。同理,在回收新生代的时候也可能有关联对象在老年代。在这位老哥的博客中找到了答案详解CMS回收机制。
重新标记:暂停所有用户线程,重新扫描堆中的对象,进行可达性分析,标记活着的对象。
并发清理:用户线程被重新激活,同时清理那些无效的对象。
说说G1收集器。为什么G1收集器要用region代替老年代和新生代?
同样从上面5个方面去说。
G1,将新生代老年代划分为一块块可以不连续的region区。这样划分的好处是,有的区域对象特别多,有的区域对象特别少,而G1会优先回收有价值的垃圾区域,这里的”价值”说的是回收所需要的时间和回收后得到的空间大小。G1即Garbage first,垃圾优先回收。
G1的其他特点:
- 为了避免全堆扫描使用RememberSet记录引用情况,在RememberSet表中,记录了其他Region中的对象指向本Region中对象的关系。RememberSet是一个键值对形式,key是其他region的起始地址,value是一个集合,里面的元素是card table的index。card table即卡表,这个在CMS的并发预处理中也用到了,目的是解决GC Root Trancing过程中新生代和老年代对象混乱的问题。
- G1可以预测停顿,这是因为G1维护了一个按照回收价值排序的优先队列,所以我们可以根据设置的时间优先回收价值最大的Region。
- G1不会产生内存空间碎片,因为G1从整体来看采用的是标记整理。之所以说是整体,是因为G1实际上在也会有分代收集行为,在新生代采用复制算法,但即使如此也不会产生碎片。
- STAB:G1并发理论的基础,这个深入起来内容挺多,真心没精力看