一、垃圾收集算法
1)标记-清除算法:标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象
----主要不足:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片
2)复制算法:将可用内存容量分为大小相等的两块,每次只使用其中一块。当这一块的内存用完了,就将还存活的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
----只需移动堆顶指针,按顺序分配内存即可,实现简单,运行高效,解决了效率问题
----代价:内存缩小为原来的一半,消耗太高
----目前普遍将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。HotSpot虚拟机默认Eden:Survivor=8:1
3) 标记-整理算法:标记出所有需要回收的对象,让所有存活的对象都向一端移动,然后直接清理掉边界之外的内存
4)分代收集算法:把java堆分为新生代和老年代,新生代使用复制算法;老年代使用“标记-清除”或“标记-整理”算法
二、HotSpot的算法实现
1)枚举根节点:在HotSpot虚拟机中,使用一组称为OopMap的数据结构直接得知哪些地方存放着对象引用
2)安全点:程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。安全点的选定以“是否具有让程序长时间执行的特征”为标准进行选定。
----关于如何让所有线程(不包括执行JNI调用的线程)在GC发生时都跑到最近的安全点上停顿下来
- 方式一:抢先式中断(目前已废弃):在GC发生时,首先把所有线程全部中断,如果发现有线程中断的地方不再安全点上,就恢复线程,让它跑到安全点上
- 方式二:主动式中断:在GC需要中断线程时,不直接操作线程,而是通过设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。轮询标志的地方和安全点是重合的,另外再加上创建对象需要分配内存的地方。
3)安全区域:指在任何一端代码片段中,引用关系不会发生变化,在这个区域的任意地方开始GC都是安全的。解决当线程处于sleep状态或blocked状态,无法响应JVM中断请求,没有分配CPU时间的问题
三、垃圾收集器
1)Serial收集器:单线程收集器,是虚拟机运行在Client模式下的默认新生代收集器。进行垃圾收集时,会暂停其他所有的工作线程,直到他收集结束
2)ParNew收集器:是Serial收集器的多线程版本,是许多运行在Server模式下的虚拟机中首选的新生代收集器(原因是除了Serial收集器外,目前只有他能与CMS收集器配合工作)
3)Parallel Scavenge收集器:新生代并行多线程收集器,使用复制算法。
CMS等收集器的关注点是尽可能的缩短垃圾收集时用户停顿时间,而Parallel Scavenge收集器的目标是达到一个可控制的吞吐量【吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)】
-XX:MaxGCPauseMillis参数用于控制最大的垃圾收集停顿时间,允许的值是一个大于0的毫秒数
-XX:GCTimeRatio参数用于直接设置吞吐量大小,允许的值是一个大于0且小于100的整数
亮点:自适应策略,通过设置-XX:+UseAdaptiveSizePolicy参数可实现动态调整以提供最合适的停顿时间(MaxGCPauseMills参数)和最大吞吐量(GCTimeRatio)
4)Serial Old收集器:单线程收集器,Serial老年代版本,使用“标记-整理”算法。主要用于给Client模式下的虚拟机使用。若在Server模式下,则用于与Parallel Scavenge收集器搭配使用或作为CMS收集器的后备预案。
5)Paraller Old收集器:多线程收集器,Parallel Scavenge老年代版本,使用“标记-整理”算法
6)CMS收集器:一种以获取最短回收停顿时间为目标的收集器,基于“标记-清除”算法实现。运作过程包括:
- 初始标记:仅标记GC Roots能直接关联到的对象
- 并发标记:进行GC Roots Trancing的过程
- 重新标记:修正并发标记期间因用户程序继续运作而标记产生变动的那一部分对象的标记记录
- 并发清除:清除垃圾对象
缺点:
- 对CPU资源非常敏感,默认启动的回收线程数是(CPU数量+3)/4;
- 无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC 的产生
- 由于基于“标记-清除”算法实现,故在收集结束时会有大量空间碎片产生
7)G1收集器:是一款面向服务端应用的垃圾收集器
特点:并行与并发,分代收集,空间整合,可预测的停顿
运作步骤:
- 初始标记:仅标记GC Roots能直接关联到的对象(耗时短)
- 并发标记:从GC Roots开始对堆中对象进行可达性分析,找出存活对象(耗时长,但可与用户程序并发运行)
- 最终标记:修正并发标记期间因用户程序继续运作而标记产生变动的那一部分对象的标记记录(需停顿线程,但可并行执行)
- 筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来指定回收计划