一、垃圾回收算法
1、分代算法
- 原理:根据对象存活周期的不同将内存分为几块,一般分为年轻代和年老代,这样我们就可以根据年轻代和年老代的特点选择合适的垃圾收集算法
- 年轻代:对象存活几率是比较小的,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集
- 年老代:对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集
2、标记算法
-
引用计数算法
-
原理:引用计数算法就是在对象中添加一个引用计数器,每当对象被增加一个引用,引用计数器的值就加1,每当对象被减少一个引用,引用计数器的值就减1,而引用计数器的值为0的对象,则被定性为垃圾对象。
-
问题:引用计数算法虽然简单高效,但JVM不选择它,因为它存在一个问题:当对象之间相互引用时,两个对象都无法成为垃圾对象。
-
示例:
/** * 引用计数算法原理及问题 */ public class MarkingAlgorithmReferenceCount { public MarkingAlgorithmReferenceCount ref; public static void main(String[] args) { //原理:对象的堆中实例存在一个引用计数器,每当被增加引用,计数器值+1,每当被减少引用,计数器值-1 MarkingAlgorithmReferenceCount obj1 = new MarkingAlgorithmReferenceCount();//obj1堆中实例引用计数+1,值为1 MarkingAlgorithmReferenceCount obj2 = new MarkingAlgorithmReferenceCount();//obj2堆中实例引用计数+1,值为1 obj1.ref = obj2;//obj2堆中实例引用计数+1,值为2 obj2.ref = obj1;//obj1堆中实例引用计数+1,值为2 obj1 = null;//obj1堆中实例引用计数-1,值为1 obj2 = null;//obj2堆中实例引用计数-1,值为1 //问题:obj1堆中实例与obj2堆中实例在相互引用,计数器的值均为1,导致本该成为垃圾对象的两个实例,不能被删除,最终会引发OOM } }
-
-
可达性分析算法
- 原理:根据对象之间的引用关系的链性和可追溯性,将特定的对象定义为GCROOT作为起始点,向下检索,检索所走过的路径被定义为引用链,在这些引用链上的对象,均为存活对象。
- GCROOT对象
- 虚拟机栈(栈帧中局部变量表)中引用的对象
- 本地方法栈(栈帧中局部变量表)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
3、回收算法
- 复制-清除算法
- 原理:将内存分为大小相同的两块A和B,当这A的内存使用完后,JVM通过可达性分析算法将A中所有的存活对象逐一复制到B中去,然后将B当作新的对象存储空间,再把A清空。
- 优点:速度快,不会产生内存碎片
- 缺点:浪费内存
- 标记-清除算法
- 原理:内存使用完后,JVM通过可达性分析算法标记所有的存活对象,再将未标记的对象进行清除
- 优点:速度快
- 缺点:产生内存碎片
- 标记-整理算法
- 原理:内存使用完后,JVM通过可达性分析算法标记所有的存活对象,再将未标记的对象进行清除,然后将所有存活对象统一向一端移动
- 优点:不产生内存碎片
- 缺点:速度慢
二、垃圾回收器
1、Serial收集器
- Serial
- 年轻代
- 复制-清除算法
- 单线程
- stop the world
- -XX:+UseSerialGC
- 组合:
- Serial Old收集器
- CMS收集器
- Serial Old
- 年老代
- 标记-整理算法
- 单线程
- stop the world
- -XX:+UseSerialOldGC
- 组合:
- Serial收集器
- ParNew收集器
- Parallel Scavenge收集器
2、ParNew收集器
- ParNew
- 年轻代
- 复制-清除算法
- 多线程
- stop the world
- -XX:+UseParNewGC
- 组合:
- Serial Old收集器
- CMS收集器
3、Parallel收集器
- Parallel Scavenge
- 年轻代
- 复制-清除算法
- 多线程
- stop the world
- -XX:+UseParallelGC
- 组合:
- Parallel Old收集器
- Serial Old收集器
- Parallel Old
- 年老代
- 标记-整理算法
- 多线程
- stop the world
- -XX:+UseParallelOldGC
- 组合:
- Parallel Scavenge收集器
4、CMS收集器
- Concurrent Mark Sweep
- 年老代
- 标记-清除算法
- 多线程
- -XX:+UseConcMarkSweepGC
- 过程:
- 初始标记
- 此阶段只标记GCROOT直连对象
- stop the world
- GC单线程(可通过参数修改为GC多线程)
- 并发标记
- 此阶段只根据初始标记的GCROOT直连对象,向下检索标记存活对象
- 用户线程
- GC多线程
- 重新标记
- 此阶段只修正并发标记过程中,标记的存活对象被用户线程污染的状态
- stop the world
- GC单线程(可通过参数修改为GC多线程)
- 并发清理
- 此阶段只清理重新标记阶段未标记的对象,通过三色标记算法规避用户线程新增对象
- 用户线程
- GC多线程
- 并发重置
- 此阶段只重置此次GC标记过的对象
- 用户线程
- GC多线程
- 初始标记
- 组合:
- Serial收集器
- ParNew收集器
- 优点:减少stop the world时间
- 缺点:
- 浮动垃圾,只能下一次GC回收
- 内存碎片,可通过参数增加整理动作,时间会进一步延长
- 并发模式失败(concurrent mode failure),GC时,由于用户线程的参与,可能又触发了GC,此时就会转换为Serial模式,可通过参数调整预留内存来避免