分代收集:新生代(复制算法),老年代(标记清除,标记整理) 、
jps -v 可查看当前JVM 使用的是那种垃圾收集器
垃圾回收器又分单线程多线程,使用。
常见的垃圾回收器如下图:垃圾回收器的连线表示搭配使用的意思,不同的颜色表示不同的算法(3种)
使用标记清除的只有CMS 一种垃圾回收器
G1是独立使用的,并且可以跨代回收。(JDK1.7之后出的)
多线程的垃圾回收器:多线程收集,也就是并行;多线程收集和多线程的应用同时进行,也就是并发;
垃圾收集器的连线是组合使用的意思,不同的字体颜色代表不同的垃圾回收算法;
单线程回收器:
Serial/Serial old: 最古老,独占式,成熟,适合单CPU服务器
多线程回收器:
ParNew:与 Serial 没什么区别,唯一的区别就是多线程收集,多cpu,停顿时间较Serial少
除了性能原因之外,在新生代除了Serial,就只有ParNew能与CMS收集器配合使用
Parallel Scavenge(Paraller GC) /Parallel Old: 关注吞吐量的垃圾收集器,高吞吐量可以高效的利用cpu时间,尽快的完成运算任务,
主要适合后台运算不太需要交换的任务。
所谓的吞吐量:吞吐量=运行代码的时间(99分钟)/(运行代码的时间(99分钟)+垃圾回收的时间(1分钟)),
99%=99(分钟)/(99分钟+1分钟),吞吐量为99%;
垃圾回收器组合:
-XX:+UseSerialGC 新生代和老年代串行收集器(Serial+Serial Old)
-XX:+UseParNewGC 新生代使用 ParNew,老年代使用 Serial Old
-XX:+UseParallelGC 新生代使用Parallel Scavenge,老年代使用 Parallel Old
简单垃圾收集器的工作原理:
重点关注两种垃圾收集器:CMS,G1(G First)
CMS(Concurrent Mark Sweep) :CMS是基于标记清除算法,以及并行和并发收集的回收器;
过程大概如下:初始标记(暂停所有线程)--》并发标记(时间长)--》重新标记--》并发清除(时间长)--》重置线程
初始标记:仅仅是标记GC Roots 判断对象是否可达,速度快,需要暂停所有线程(Stop the World)
并发标记:从GC Roots 开始对堆中的对象进行可达性分析,找到存活对象,整个生命周期中耗时最长,不需要停顿
重新标记:为了修正并发标记期间用户对程序产生的对象的变化的标记,需要停顿,这个时间比初始标记要长,比并发要短
并发清除:垃圾开始回收,不需要停顿
优点:由于耗时最长的并发标记和并非清理都是和用户线程一起进行的,所以总体上CMS给人的感觉就是没停顿;
缺点: CPU要求高,因为并发是占用量资源的;
标记清除算法导致的垃圾碎片,
并发标记会产生浮动垃圾, 需要等下一次垃圾回收来清理,占用内存,需要预留一部分空间来存放浮动垃圾;
G1(Garbage-First)垃圾回收器:基于复制和标记整理算法的并行,并发收集器;(Global Concurrent Marking)
一般要求cup内存空间足够大,内存过小不建议用,失败会启用FullGC(serial Old)
过程大概如下:初始标记(暂停所有线程)--》并发标记---》最终标记(暂停所有线程)--》筛选回收
初始标记:仅仅标记一下GC Roots 能直接关联到的对象,需要停顿,耗时短
并发标记:进行可达性分析,找到存活对象,耗时长,与用户线程同时进程
最终标记:为了修正用户并发标记期间对标记对象产生变化的那一部分对象记录,需要停顿
筛选回收:首先对各个Region中的回收价值和成本进行排序(后台维护了优先序列表),
根据用户所期望的停顿时间来制定回收计划
此阶段是可以跟用户线程并发进行的,因为只回收一部分Region ,所以时间可控
而且停顿用户线程将大幅度提高效率
特点: 内存布局发生了改变
空间整合,不会产生内存碎片
化整为零,分而治之,可预测的停顿(默认200ms),可根据用户设定的回收时间来提供回收方案
比如:100g 内存,分成10份,每份就是10g(G First 的意思就是急需回收的意思)
模式:
Young GC:主要对Eden区Survivor区(Form,To)进行回收
Mixed GC:Survivor区与Old区,Humongous (大对象)
G1主要参数配置:
-XX:+UseG1GC,使用G1垃圾回收器
-XX:G1HeapRegionSize = n ,设置每个Region 的大小,并非最终
-XX:MaxGCPauseMillis ,设置G1收集过程目标时间,默认是200ms,不是硬性条件
-XX:G1NewSizePercent, 新生代最小值,默认是5%
-XX:G1MaxNewSizePercent, 新生代最大值,默认是60%
-XX:ParallelGCThreads ,STW 期间,并行GC的线程数
-XX:ConcGCThreads = n, 并发标记阶段,并行执行的线程数
-XX:InitiatingHeapOccupancyPercent 设置触发标记周期的Java堆占用阈值。默认值是45%,
这里的java堆占比值得是non_young_capacity_bytes,包括old+humongous
垃圾回收器的重要参数(使用-XX:):