目录
垃圾收集器种类
HotSpot虚拟机所包含的收集器
垃圾收集器部分源码
垃圾收集器后台日志参数说明与配对关系
1、串行垃圾收集器
串行垃圾收集器运行示意图
1)、编写测试代码
2)、设置垃圾回收为串行收集器
3)、启动程序,GC日志信息解读
2、并行垃圾收集器
并行垃圾收集器-ParNew运行示意图
1)、编写测试代码
2)、设置垃圾回收为并行收集器ParNew
3)、启动程序,GC日志信息解读
并行垃圾收集器-ParallelGC运行示意图
1)、编写测试代码
2)、设置垃圾回收为并行收集器ParallelGC
3)、启动程序,GC日志信息解读
3、CMS垃圾收集器
CMS垃圾收集器运行示意图:
1)、编写测试代码
2)、设置CMS垃圾回收参数
3)、启动程序,GC日志信息解读
4、G1垃圾收集器
G1垃圾收集器(将新生代,老年代的物理空间划分取消了),示意图如下
G1垃圾收集器(G1算法将堆划分为若干个区域-Region)
G1垃圾收集器原理
G1垃圾回收模式:Young GC
G1垃圾回收模式:Mixed GC
G1垃圾收集器运行示意图
1)、编写测试代码
2)、G1垃圾收集器相关参数:
3)、设置G1垃圾回收参数
4)、启动程序,GC日志信息解读
G1垃圾收集器 vs CMS垃圾收集器
G1垃圾收集器优化建议
可视化GC日志分析工具
1、GC日志输出参数
2、GC Easy可视化工具
GC Easy查看gc报告
串行垃圾收集器是最基本的、发展历史最悠久的收集器。
特点:单线程、简单高效(与其他收集器的单线程相比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。收集器进行垃圾回收时,必须暂停其他所有的工作线程,直到它结束(Stop The World)。
import java.util.UUID;
/**************************************************
*
* @title
*
**************************************************/
public class TestGC1 {
/**
* java -XX:+PrintCommandLineFlags -version
*
* @param args
*/
public static void main(String[] args) {
String str = "smart";
while (true) {
str += str + UUID.randomUUID();
str.intern();
}
}
}
在程序运行参数中添加2个参数,如下:
-XX:+UseSerialGC 指定年轻代和老年代都使用串行垃圾收集器
-XX:+PrintGCDetails 打印垃圾回收的详细信息
并行垃圾收集器在串行垃圾收集器的基础之上做了改进,将单线程改为了多线程进行垃圾回收,这样可以缩短垃圾回收的时间。(这里是指,并行能力较强的机器)
当然了,并行垃圾收集器在收集的过程中也会暂停应用程序,这个和串行垃圾回收器是一样的,只是并行执行,速度更快些,暂停的时间更短一些。
ParNew垃圾收集器
通过-XX:+UseParNewGC参数设置年轻代使用ParNew回收器,老年代使用的依然是串行收集器
通过-XX:+ParallelGCThreads可以限制GC线程数量,默认开启和cpu数目相同的线程数
同之前的代码
在程序运行参数中添加1个参数,如下
-XX:+UseParNewGC
-Xms8m
-Xmx8m
-XX:+PrintGCDetails
-XX:+PrintCommandLineFlags
解释:
ParNew - 年轻代ParallelNew垃圾收集器
Tenured - 老年代Serial Old垃圾收集器
ParallelGC垃圾收集器
ParallelGC收集器工作机制和ParNewGC收集器一样,只是在此基础之上,新增了两个和系统吞吐量相关的参数,使得其使用起来更加的灵活和高效。适合大数据计算。
同之前代码
ParallelGC垃圾收集器相关参数如下:
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:MaxGCPauseMillis
-XX:ParallelGCThreads=N
解释:
(1)-XX:+UseParallelGC、-XX:+UseParallelOldGC这两个参数可以相互激活,也就是说,配置一个可以,可以不用配置另外一个;
(2)-XX:MaxGCPauseMillis - 最大停顿时间,其值为大于0的毫秒数,垃圾收集器尽可能保证回收的耗时不超过设定的值,但是并不是越小越好,如果值设置太小,那么GC的频率会提高,这样吞吐量就降低了。
(3)-XX:GCTimeRatio=99 - 控制吞吐量大小,其值为0-100的整数,表示吞吐量,默认值是99,表示允许1%的垃圾回收时间占比。
(4)-XX:ParallelGCThreads=N - 控制垃圾回收线程数,此参数设置年轻代并行收集器的线程数,一般与CPU数量相等,过多的线程数量会影响垃圾回收以及整个程序的性能。
(5)-XX:UseAdaptiveSizePolicy - ParallelGC可以自动调整Survivor空间,大部分的程序使用自动调整可以满足要求,个别应用在需要的情况下可以关闭自动调整,进行手动调整
具体:请参考https://www.cnblogs.com/ysqzy/p/16930918.html
解释:
PSYoungGen - Parallel Scavenge
ParOldGen - Parallel Old Generation
CMS全称 Concurrent Mark Sweep,是一款并发的、使用标记-清除算法的垃圾回收器,该回收器是针对老年代垃圾回收的,通过参数-XX:+UseConcMarkSweepGC进行设置。适合互联网,响应时间短、CPU核数多的应用。
CMS垃圾回收器的执行过程如下:
执行过程拆解:
(1)初始标记
(2)并发标记
(3)预处理
(4)重新标记
(6)重置线程
同之前的代码
-‐XX:+UseConcMarkSweepGC
注意:开启后将采用ParNew+CMS+Serial Old收集器组合
G1垃圾收集器是在jdk1.7update4中正式使用的全新的垃圾收集器,oracle官方在jdk9中将G1变成默认的垃圾收集器,以替代CMS。
G1的设计原则就是简化JVM性能调优,开发人员只需要简单的三步即可完成调优:
G1垃圾收集器相对比其他收集器而言,最大的区别在于它取消了年轻代、老年代的物理划分,取而代之的是将堆划分为若干个区域(Region),这些区域中包含了有逻辑上的年轻代、老年代区域。这样做的好处就是,我们再也不用单独的空间对每个代进行设置了,不用担心每个代内存是否足够。
解释:
G1每个堆区域最大32M,默认划分2048个区域,也就是说最大64G内存。
在G1划分的区域中,年轻代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者Survivor空间,G1收集器通过将对象从一个区域复制到另外一个区域,完成了清理工作。
这就意味着,在正常的处理过程中,G1完成了堆的压缩(至少是部分堆的压缩),这样也就不会有cms内存碎片问题的存在了。
在G1中,有一种特殊的区域,叫Humongous区域。如果一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象。
这些巨型对象,默认直接会被分配在老年代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。
为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。
针对Young GC主要是对Eden区进行GC,它在Eden空间耗尽时会被触发。Eden空间的数据移动到Survivor空间中,如果Survivor空间不够,Eden空间的部分数据会直接晋升到年老代空间。
Survivor区的数据移动到新Survivor区中,也有部分数据晋升到老年代空间中。最终Eden空间的数据为空,GC停止工作,应用线程继续执行。
分2步:
当-XX:InitiatingHeapOccupancyPercent=N (老年代大小占堆百分比达45%的时候触发mixed GC),触发MixedGC,执行下面流程
同之前的代码
-XX:UseG1GC
-XX:MaxGCPauseMillis - 执行最大GC暂停时间
-XX:G1HeapRegionSize=N (1-32M,默认2048个分区,最大64G内存)
-XX:G1ReservePercent=N - 预留空闲空间,避免内存溢出,默认10%,一般不能设置
-XX:ConcGCThreads=N - GC线程数
-XX:InitiatingHeapOccupancyPercent=N (老年代大小占堆百分比达45%的时候触发mixed GC)
‐XX:+PrintGC 输出GC日志
‐XX:+PrintGCDetails 输出GC的详细日志
‐XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
‐XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013‐05‐04T21:53:59.234+0800)
‐XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
‐Xloggc:F://test//gc.log 日志文件的输出路径
年轻代大小
暂停时间目标不要太过严苛
前面通过-XX:+PrintGCDetails可以对GC日志进行打印,我们就可以在控制台查看,这样虽然可以查看GC的信息,但是并不直观,可以借助于第三方的GC日志分析工具进行查看。 在日志打印输出涉及到的参数如下:
‐XX:+PrintGC 输出GC日志
‐XX:+PrintGCDetails 输出GC的详细日志
‐XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
‐XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013‐05‐04T21:53:59.234+0800)
‐XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
‐Xloggc:F://test//gc.log 日志文件的输出路径
测试:
最后生成gc.log,我们利用下面的可视化工具进行分析。
GC Easy是一款在线的可视化工具,易用、功能强大, GCEasy官网地址:Universal JVM GC analyzer - Java Garbage collection log analysis made easy
打开官网上传gc.log,点击分析即可。分析完之后它会给我们出相关的分析报告,那查看指标如何解读呢?