JVM垃圾收集算法学习笔记

Posted 等待戈多儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM垃圾收集算法学习笔记相关的知识,希望对你有一定的参考价值。

垃圾收集(Garbage Collection)与垃圾回收是一个意思。

了解GC和内存分配,有助于排查各种内存溢出和内存泄漏问题,当系统达到更高的并发量时,需要对这些自动化的技术(GC)实施必要的监控和调节。

程序计数器、虚拟机栈、本地方法栈是跟随线程的,栈中的栈帧随着方法的进入和退出有条不紊的执行出栈和入栈操作,每一个栈帧分配多少内存基本上是在类结构确定下来的时候确定的(编译期可知),这几个区域在方法结束或者线程结束时内存就随着回收了,所以不用考虑垃圾收集。

但是堆和方法区,只有程序在运行期间才知道会程序会创建哪些对象,内存的分配和回收是动态的,所以垃圾收集关注的是这两个部分。


1.判断对象是不是要回收:可达性分析算法

使用可达性分析算法而不是引用计数算法。因为引用计数算法很难解决对象之间相互循环引用的问题。

可达性分析算法的基本思路是通过一些列称为GC Roots的对象作为起始点,从这些起始点向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(GC Roots到这个对象不可达),则证明这个对象是不可用的。

但是不可达的对象也不是直接要被回收的,至少还要经历两次标记过程:第一次标记的时候进行一次筛选,如果对象没有通过finalize()(引用指向this)方法(此方法只能逃脱一次),则被进行第二次标记,如果还没有逃脱就基本被回收了。

可以作为GC Roots的对象包括:

(1)JVM栈(栈帧中的本地变量表)中引用的对象

(2)方法区中类静态属性引用的对象

(3)方法区中常量引用的对象

(4)本地方法栈中JNI(一般的Native方法)引用的对象

四种引用类型:

引用:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。

(1)强引用。new 出来的对象,只要引用在垃圾收集器永远不会回收。

(2)软引用。描述还有用但非必需的(类似缓存)。软引用关联的对象,在系统内存溢出之前,对其将进行第二次回收。

(3)弱引用。关联非必需对象。只能生存到下一次垃圾回收之前。

(4)虚引用。不能通过虚引用取得实例,能在这个对象被回收时受到一个系统通知。


JVM规范可以不要求JVM在方法区实现垃圾收集,因为性价比一般较低,堆中一般可回收70%-95%的空间。方法区中主要回收废弃的常量和无用的类。

判定是否废弃常量只需要判定别的地方有无引用,如果没有则被移出常量池。

判定无用的类(同时满足下面3个条件):

(1)该类的所有实例都已经被回收,Java 堆中不存在该类的任何实例

(2)加载该类的ClassLoader已经被回收

(3)该类的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射机制访问该类的方法

2.垃圾收集算法

(1)标记-清除算法

首先标记处所要回收的对象,标记完成后统一清除。

缺点:标记效率低,清除效率低,回收结束后会产生大量不连续的内存碎片(没有足够连续空间分配内存,提前触发另一次垃圾回收)


(2)复制算法(Survivor的from和to区,from和to会互换角色)

将内存容量划分大小相等的两块,每次只使用其中一块。一块用完,就将存活的对象复制到另一块,然后把使用过的一块一次清除。不用考虑内存碎片,每次只要移动顶端指针,按顺序分配内存即可,实现简单运行高效。

缺点:内存缩小为原来的一般,代价高。浪费50%的空间。


(3)标记-整理算法
标记完成后,将存活的对象移动到一端,然后清除边界以外的内存。使用于对象存活率高的老年代。


(4)分代收集算法

根据对象存活周期不同,将内存划分为几块,进行垃圾收集。Java堆一般分为老年代和新生代,根据各个年代的特点采用适当的收集算法。

新生代:每次垃圾收集都有大量对象死去,少量对象存活,采用复制算法。

老年代:对象存活率高,没有额外空间进行内存分配担保,适合用标记-清除或者标记整理。


并行:多条垃圾收集线程并行工作,用户线程仍然等待。

并发:用户线程与垃圾收集线程同时执行。

垃圾收集器:

Serial 收集器:新生代单线程收集器,工作时必须暂停所有其他工作线程,直到收集结束。目前仅运行于JVM的Client模式下。

Parnew 收集器:Serial 收集器的多线程版本。使用复制算法。Server模式下JVM首选的新生代收集器(除Serial 外只有Parnew 能与CMS收集器配合工作)

Parallel Scavenge 收集器:新生代多线程收集器,使用复制算法。特点是吞吐量优先。动态调整参数提供最合适的停顿时间和最大的吞吐量:GC自适应调节策略。parallel:平行的;Scavenge:清除。


Serial Old收集器:Serial 收集器的老年代版本。使用标记-整理算法。

Parallel Old 收集器:Parallel Scnvenge 收集器的;老年代版本。使用标记-整理算法。适用于CPU敏感、注重吞吐量的场合。

CMS 收集器:Concurrent Mark Sweep 并发标记-清除。重视响应速度,适用于互联网和B/S系统的服务端上。初始标记还是需要Stop the world 但是速度很快。缺点:

CPU资源敏感,无法浮动处理垃圾,会有大量空间碎片产生。

G1 收集器:可替换CMS 收集器 ,当今(2016年)收集器技术发展的前沿成果。




内存分配策略:

(1)对象优先分配在Eden

(2)大对象直接进入老年代

(3)长期存活的对象将进入老年代

(4)幸存区相同年龄对象的占幸存区空间的多于其一半,将进入老年代

(5)空间担保分配(老年代剩余空间需多于幸存区的一半,否则要Full GC)









以上是关于JVM垃圾收集算法学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

JVM垃圾收集—垃圾收集器及常见组合参数

JVM垃圾收集算法学习笔记

JVM学习笔记GC——JAVA预言的垃圾回收

JVM之GI收集器

JVM的垃圾收集算法

JVM的垃圾收集算法