JVM(二)垃圾回收及收集器

三、垃圾回收

1. 确定对象是否被销毁的方法

1.1 引用计数算法

1.1.1 原理

(1)为对象添加一个引用计数器
(2)每当对象在一个地方被引用,则该计数器加 1,每当对象引用失效时,计数器减 1。
(3)当计数器为 0 的时候,就表明该对象没有被引用。

1.1.2 缺点

无法处理循环引用的问题。

1.2 可达性分析算法(jvm采用)

1.2.1 图JVM(二)垃圾回收及收集器_第1张图片
1.2.2 图解说

(1)通过 “GC Roots” 的根节点开始,沿着引用链进行搜索。
(2)绿色部分的对象都在 GC Roots 的引用链上,就不会被垃圾回收器回收,
(3)灰色部分的对象没有在引用链上,就被判定为可回收对象。

2.jvm垃圾回收算法

2.1 标记–清除算法

对无效的对象进行标记,然后清除。
JVM(二)垃圾回收及收集器_第2张图片

2.2 复制算法

把Java 堆分成两块,每次垃圾回收时只使用其中一块,然后把存活的对象全部移动到另一块区域。

JVM(二)垃圾回收及收集器_第3张图片

2.3 标记–整理算法

2.3.1 概念

(1)结合前面两个算法特点
(2)标记的存活对象移动到堆的一端
(3)清理存活对象以外的区域

2.3.2 优缺点

(1)优点:避免了内存碎片,也不存在堆空间浪费
(2) 缺点:
每次进行垃圾回收的时候,都要暂停所有的用户线程;特别是对老年代的对象回收,则需要更长的回收时间,用户体验差。

3.垃圾收集器

高效记忆:

(1)单行程(单线程)的Siri(serial)老(serial old)了,收集信息速度太慢了,于是派来了新( ParNew)的多行程的语音助手来帮忙。
(2)可是收集量还是不够大,于是又派来了斯克文(Parallel Scavenge)提高收集量,而且和之前派来了老(parallel Old)的一起收集很合拍。
(3)收集量越来越多累得他们不得不停顿休息。还好西姆斯(CMS)也来帮忙收集了。
而且他不仅停顿休息少而且收集量也大,只是有一点,收集完比较多碎片化的东西。
不过他找到朋友G1来帮他解决了这个问题。

3.1 Serial 收集器

(1)最基础、最悠久的收集器,是一个单线程工作的收集器。
(2)清理堆空间时,进行 Minor gc 和Full GC,所有的应用线程都会被暂停。
JVM(二)垃圾回收及收集器_第4张图片

3.2 ParNew 收集器

(1)是 Serial 收集器的多线程并行版本,同时使用多条线程进行垃圾收集。
(2)其余包括 Serial 收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与 Serial 收集器完全一致。

JVM(二)垃圾回收及收集器_第5张图片

3.3 Parallel Scavenge 收集器

(1)新生代收集器,基于标记——复制算法实现,
(2)能够并行收集的多线程收集器,和 ParNew 非常相似。
(3)目标则是达到一个可控制的吞吐量(Throughput)。

备注吞吐量
a.处理器用于运行用户代码的时间与处理器总消耗时间的比值。
b.如:虚拟机完成某个任务,用户代码加上垃圾收集总共耗费了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是 99%。

3.4 Serial Old 收集器

Serial 收集器的老年代版本,单线程收集器,使用 “标记-整理算法”。
JVM(二)垃圾回收及收集器_第6张图片

3.5 Parallel Old 收集器

是 Parallel Scavenge 收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。
JVM(二)垃圾回收及收集器_第7张图片

3.6 CMS收集器

Concurrent Mark Sweep

3.6.1 概念

(1)目标是为了消除 Parallel 收集器和 Serial 收集器 Full gc 周期中的长时间停顿。
(2)在 Minor gc 时会暂停所有的应用线程,并以多线程的方式进行垃圾回收。

JVM(二)垃圾回收及收集器_第8张图片

3.6.2 步骤
(1)初始标记(CMS initial mark) :

仅仅标记一下GC Roots能直接关联到的对象,速度很快。

(2)并发标记(CMS concurrent mark) :

a.从GC Roots的直接关联对象,开始遍历整个对象图的过程。
b.这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行;

(3)重新标记(CMS remark) :

a.是为了修正并发标记期间,因用户程序继续运作,而导致标记产生变动那一部分对象的标记记录,
b.这个阶段的停顿时间通常会比初始标记阶段稍长一 些,但也远比并发标记阶段的时间短;

(4)并发清除(CMS concurrent sweep):

a.并发清除阶段,清理删除掉标记阶段判断的已经死亡的 对象,
b.由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。

3.7 G1收集器

3.7.1 概念

(1)Garbage-First,垃圾优先。
(2)服务类型收集器,针对配备多核处理器及大容量内存的机器。
(3)可设置垃圾收集暂停时间,高吞吐量,CPU利用率高。
(4)G1保留了年轻代和老年代的概念,但不再是物理隔阂了,它们都是(可以不连续)Region的集合,年轻代和老年代会动态变化甚至相互转换。
(5)重要参数
a.XX:MaxGCPauseTimeMillis :
设置GC可以暂停虚拟机的最大时间量。
默认:停顿时间200ms
b.-Xmx - 允许虚拟机的最大堆空间。

JVM(二)垃圾回收及收集器_第9张图片

3.7.2 特点

(1)并行与并发
(2)分代收集
(3)空间整合
整体:基于标记-整理算法实现
局部:基于标记-复制算法实现
(4)可预测的停顿
G1除了追求低停顿(CMS也是)外,还能建立可预测的停顿时间模型(后台维护的优先列表)

3.7.3 垃圾收集分类
3.7.3.1 YoungGC

(1)初始值只占堆内存5%
(2)若Eden区回收时间远小于-XX:MaxGCPauseMills设定的值,则增加年轻代的region,继续给新对象存放,不会马上做Young GC。
(3)若回收时间接近参数 -XX:MaxGCPauseMills设定值,则触发Young GC

3.7.3.2 MixedGC:混合收集

(1)老年代的堆占有率达到参数-XX:InitiatingHeapOccupancyPercent设定的值触发
(2)回收所有的年轻代和部分老年代(根据筛选回收阶段计算优先级后排序)以及大对象区。
(3)正常情况G1的垃圾收集是先做MixedGC,主要使用复制算法,
需要把各个region中存活的对象拷贝到别的region里去,
拷贝过程中如果发现没有足够的空region能够承载拷贝对象就会触发一次Full GC。

3.7.3.3 Full GC

停止系统程序,然后采用单线程进行标记、清理、压缩整理,以空闲出来一批Region,来供下一次MixedGC使用,这个过程非常耗时。

3.7.4 适合场景

(1)50%以上的堆被存活对象占用
(2)对象分配和晋升的速度变化非常大:前提是大内存的主机才有优势,否则还不如其他
(3)垃圾回收时间特别长,超过1秒
(4)8GB以上的堆内存(建议值)
共2048个Region,内存太小的话每个Region也很小,很容易就超过Region的一半被识别为超大对象,这样Humongous区东西会很多,反而不能很好的进行GC收集
(5)停顿时间是500ms以内

3.8 垃圾收集器总结

3.8.1 重要概念
3.8.1.1 jvm参数打印jdk、收集器信息
   -XX:+PrintCommandLineFlags  -version

# 必备
# 开启GC
-verbose:gc (-XX:+PrintGC)
# 开启打印GC详情
-XX:+PrintGCDetails 
# 打印GC时间
-XX:+PrintGCDateStamps 
# 打印对象分布情况
-XX:+PrintTenuringDistribution 
# GC后打印堆数据
-XX:+PrintHeapAtGC 
# 打印Reference处理信息:强引用/弱引用/软引用/虚引用/finalize
-XX:+PrintReferenceGC 
# 打印STW时间
-XX:+PrintGCApplicationStoppedTime

# 可选
# 打印safepoint信息
-XX:+PrintSafepointStatistics 
-XX:PrintSafepointStatisticsCount=1

# GC日志输出的文件路径(-Xloggc:D:/log/gcc.log)
-Xloggc:/path/to/gc-%t.log
# 开启日志文件分割
-XX:+UseGCLogFileRotation 
# 最多分割几个文件,超过之后从头文件开始写
-XX:NumberOfGCLogFiles=14
# 每个文件上限大小,超过就触发分割
-XX:GCLogFileSize=100M

其他参数详细如下:
JVM入门教程第14讲:JVM参数之GC日志配置

3.8.1.2 收集器并发与并行

(1)并发
是指GC可以在应用程序运行时执行工作,但是G1不能在应用程序运行时执行所有的工作,而且仍然有停止世界的事件。
(2)并行
是指一个GC可以使用多个线程来执行其工作。

3.8.1.3 收集器吞吐量

吞吐量=用户代码运行时间/(代码运行时间+垃圾收集时间)

3.8.2 java8默认:Paralle收集器
3.8.2.1 年轻代:Parallel Scavenge收集器

(1)使用复制算法,目标是达到一个可控制的吞吐量
(2)重要参数:-XX:UserAdaptiveSizePolicy
a.该参数激活后,不需要人工的指定新生代大小(-Xmn)、Eden与Surivivor区的比例,晋升老年代对象大小等参数
b.虚拟机会根据当前系统运行情况,收集性能监控信息,动态调整这些参数,以提供最合适的停顿时间、最大的吞吐量。

3.8.2.2 老年代:Parallel Old收集器

(1)使用标记-整理算法,支持多线程并行收集。
(2)弥补了之前Parallel Scavenge收集器与别的优秀的老年代收集器不搭的情况。

3.8.3 比较

(1)内存效率(时间复杂度):复制算法>标记清除算法>标记整理(压缩)算法
(2)内存整齐度:标记整理(压缩)算法=复制算法>标记清除算法
(3)内存利用率:标记整理(压缩)算法=标记清除算法>复制算法

JVM(二)垃圾回收及收集器_第10张图片

四、GC

1.GC类型

1.1 分类

(1)Minor GC/Young GC:针对新生代的垃圾收集;
(2)Major GC/Old GC:针对老年代的垃圾收集。
(3)Full GC:针对整个 Java 堆以及方法区的垃圾收集。
JVM(二)垃圾回收及收集器_第11张图片

1.2 Minor GC

(1)复制算法,收集间隔较短,年轻代堆空间紧张时会触发。
(2)初次被创建的对象存放在新生代的 Eden 区,当第一次触发 Minor GC,Eden 区存活的对象被转移到 Survivor区 的某一块区域。
(3)再次触发 Minor GC 的时候,Eden区的对象连同一块 Survivor 区的对象一起,被转移到了另一块 Survivor 区。

JVM(二)垃圾回收及收集器_第12张图片

1.3 Full GC

(1)标记整理算法,非常耗时,老年代堆空间满了触发。
(2)期间会停止所有线程等待 GC 的完成。

JVM(二)垃圾回收及收集器_第13张图片

2.GC日志

2.1 GC 日志开启

JVM(二)垃圾回收及收集器_第14张图片

JVM(二)垃圾回收及收集器_第15张图片

2.2 GC 日志的理解

JVM(二)垃圾回收及收集器_第16张图片

Full GC 日志:
JVM(二)垃圾回收及收集器_第17张图片






上一篇跳转 ---- JVM(一)常见知识点及概述                 下一篇跳转 ---- JVM(三)性能调优及实战


参考链接1

参考链接2


随心所往,看见未来。Follow your heart,see light!

欢迎点赞、关注、留言,收藏及转发,一起学习、交流!

你可能感兴趣的:(后端Java,开发学习拓展,java,jvm,算法)