文章目录
(持续更新中… …CMS and G1)
概述
如何判断对象存活
引用计数法
根可达算法
which instances are root?
JVM stack,native method stack,run-time constant pool,static references in menthod area,Clazz
GC Roots的对象:
1、在虚拟机栈(栈帧中的本地变量表)中引用的对象,如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
2、在方法区中类静态属性引用的对象,如Java类的引用类型静态变量。
3、在方法区中常量引用的对象,如字符串常量池(String Table)里的引用。
4、在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
5、Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
6、所有被同步锁(synchronized关键字)持有的对象。
7、反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
STW:
所有收集器在根节点枚举这一步骤时都是必须暂停用户线程“Stop The World”在分析过程中,根节点集合的对象引用关系必须保持不变,即使是号称停顿时间可控,或者(几乎)不会发生停顿的CMS、G1、ZGC等收集器,枚举根节点时也是必须要停顿。
OopMap:
OopMap作用:快速找到GC ROOTS,当所有线程停下来的时候,并不需要一个不漏的检查完所有执行上下文和全局引用位置,虚拟机应该是有办法直接知道哪些地方存放着对象引用。在HotSpot的实现中,是使用一组称为OopMap的数据结构来达到目的的。
OopMap存储两种对象引用:1、对象内的引用。2、栈、寄存器中引用。
Safe Point:
安全点就是程序能够停顿的位置。即程序不是在任何时候停顿下来进行GC,只有到了安全点才去更新OopMap和停顿,等待GC完成在继续执行。
GC算法(垃圾回收算法)
分代收集理论
标记-清除算法
标记-清除算法(Mark-Sweep)是最早出现也是最基础的垃圾收集算法,分为“标记”和“清除”两个阶段,从根集合(GC Roots)进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的死亡对象进行回收标记回收。
主要缺点:
第一执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低。
第二内存空间碎片化问题,标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
复制算法
标记-复制算法(Semispace Copying):将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
主要缺点:
第一Copying算法的效率跟存活对象的数目多少有很大的关系,如果存活对象很多,那么Copying算法的效率将会大大降低。
第二将可用内存缩小为了原来的一半,空间浪费。
标记-整理算法
标记-整理算法(Mark-Compact) 标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。
主要缺点:
进过标记后如果有大量存活对象,移动存活对象,并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用程序才能进行 (Stop The World)。
垃圾回收器
概述
垃圾收集器没有在任何规范中进行过多的规定,可以由不同的厂商,不同版本的JVM来实现。
由于JDK的版本处于高速迭代过程中,因此java发展至今已经衍生了众多的GC版本。
垃圾回收器分类
1、按线程数分,可分为串行垃圾回收器和并行垃圾回收器。
2、按工作模式分,可以分为并发式垃圾回收器和独占式垃圾回收器。
3、按碎片处理方式分,可分为压缩式垃圾回收器和非压缩式垃圾回收器。
4、按工作的内存空间分,可分为年起代垃圾收集器和老年代垃圾收集器。
评估GC的性能指标
1、吞吐量:运行用户代码的时间占总时间的比例 (总运行时间: 程序运行时间+内存回收时间)
2、垃圾收集开销:吞吐量的补数,垃圾收集器所用时间与总时间的比例
3、暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间
4、收集频率:相对于应用程序的执行,收集操作发生的频率
5、内存占用:Java堆区所占的内存大小
6、快速:一个对象从诞生到被回收所经历的时间
这三者共同构成一个"不可能三角",三者总体的表现随着技术的进步越来越好,一款优秀的收集器通常最多同时满足其中两项。现在标准:在最大吞吐量优先的情况下,降低暂停时间。
吞吐量(throughput)
1、吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)
2、高吞吐量的情况下,应用程序能容忍较高的暂停时间,因此高吞吐量的应用程序由更长的时间基准,快速响应是不必考虑的
暂停时间(pause time)
1、暂停时间是指一个时间段内应用程序线程暂停,让GC线程执行的状态
如果说收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现。
JDK1.8默认的垃圾回收:PS + ParallelOld。
Serial收集器
a stop-the-world,copying collertor which uses a single GC thread.
单CPU效率最高
虚拟机是Client模式的默认垃圾回收器。
Parallel收集器
ParallelNew
- a stop-the-world, copying collector which uses multiple GC threads.
- it differs from “Parallel Scavenge” in that it has enhancements that make it usable with CMS.
- For example, “ParNew” does the synchronization needed so that it can during the concurrent phases of CMS.
- 默认线程数为CPU的核数。
Parallel Scavenge
- a stop-the-world, copying collector which uses multiple GC threads.
ParallelNew vs Parallel Scavenge
- PN响应时间优先。配合CMS使用。
- PS吞吐量优先。
- 延伸阅读:HotSpot Virtual Machine Garbage Collection Tuning Guide
Parallel Old收集器
CMS收集器
三色标记算法
CMS解决方案:Incremental Update
所以,CMS的remark阶段,必须从头扫描一遍。
JVM参数:
java -XX:+PrintFlagsFinal | more
java -XX:+PrintFlagsFinal | wc -l
G1收集器
常用的收集器组合
参考资料
- https://blogs.oracle.com/jonthecollector/our-collectors
- https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
- http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
- http://www.ityouknow.com/jvm/2017/08/29/GC-garbage-collection.html