标签:
这一节我们来总结一下JVM垃圾收集器方面的东西。
GC Roots的判定:
1、虚拟机栈(栈帧中的本地变量表)中引用的对象
2、方法区中静态属性引用的对象
3、方法区中常量引用的对象
4、本地方法栈中JNI(即一般说的Native方法)引用的对象
判断引用是否无效的过程分为三个阶段
1、当JVM进行垃圾收集时,JVM使用可达性分析算法进行分析,如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,此时该对象将被第一次标记,并进行一次筛选,筛选的条件是此对象有没有必要执行finalize()方法,如果对象没有覆盖该方法,或者该方法已经被虚拟机调用过了,虚拟机将这两种情况都视为“没有必要执行”。
2、如果该对象被判定为有必要执行finalize()方法,那么对象将会被放置到一个叫做F-Queue的队列中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的执行是指虚拟机会触发这个方法,但并不承若会等待它运行结束。因为一个对象可能在finalize()方法中执行缓慢,或者发生了死循环,这将导致该队列中的其他对象长期处于等待阶段,甚至导致整个内存系统的奔溃。
3、F-Queue中的标记筛选。
finalize()方法是对象逃脱死亡命运的最后一次机会,然后GC将对F-Queue中的对象进行第二次小规模的标记。如果对象在finalize()方法中成功拯救了自己,即与引用链上的任何一个对象建立关联,那么在第二次标记的时候,该算法将被移出F-Queue的集合,如果对象这个时候还没有逃脱,那基本上它就真的被回收了。
目前比较主流的垃圾收集算法有四种:标记-清除算法、复制算法、标记-整理算法、分代收集算法。具体分析对比如下:
分类 | 标记-清除算法(Mark-Sweep) | 复制算法(Coping) | 标志-整理算法(Mark-Compact) | 分代收集算法(Generational Collection) |
---|---|---|---|---|
进行整理 | 否 | 是 | 是 | 是 |
算法实现过程 | 该算法分为两个过程:标记和清除。先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的要回收的对象。 | 将内存按容量划分为大小相等的两块区域,每次使用其中的一块,当一块的内存用完了,执行GC算法时将还存活的对象整理复制到另外一块上,然后清理所有的内存块。 | 该算法分为两个过程:标记和整理。首先标记出所有需要回收的对象,然后让存活的对象都向内存的一端移动,然后直接清除掉端边界以外的内存。 | 根据对象存活周期的不同将内存划分为几块,一般是划分为新生代和老年代,然后根据各个年代的特点采用不同的最适当的收集算法。 |
优点 | 简单,易于实现 | 内存分配时算法不产生内存碎片 | 内存分配时算法不产生内存碎片,也比较易于实现 | 分代收集,效率较高 |
缺点 | 1、效率低 2、会产生大量不连续的内存碎片 | 空间消耗太大,内存被压缩为原来的一半 | 算法复杂度大,执行步骤较多 | 算法复杂度大,执行步骤较多 |
常见的JVM垃圾收集器有七种,具体如下图所示:
最后,我们总结一下JVM中的垃圾收集器:
分类 | 所属分代 | 使用线程 | 使用算法 |
---|---|---|---|
Serial | 新生代 | 单线程 | 复制(新)、标记-整理(老) |
ParNew | 新生代 | 多线程 | 复制(新)、标记-整理(老) |
Parallel Scavenge | 新生代 | 多线程 | 吞吐量优先算法 |
Serial Old | 老生代 | 单线程 | 复制(新)、标记-整理(老) |
Parallel Old | 老生代 | 多线程 | 复制(新)、标记-整理(老) |
CMS | 老生代 | 多线程 | 标记-清除算法(初始标记、并发标记、重新标记、并发清除) |
G1 | 新生代&&老生代 | 多线程 | 标记-整理算法(初始标记、并发标记、最终标记、筛选回收) |
标签:
原文地址:http://www.cnblogs.com/zhouyuqin/p/5164060.html