JVM垃圾回收
垃圾收集器总览
HotSpot虚拟机中的7种垃圾收集器:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1
JDK7 8,HotSpot虚拟机所有收集器及组合连线,如下图:
年轻代垃圾收集器
1.Serial
Serial(串行)垃圾收集器是最基本、发展历史最悠久的收集器;
JDK1.3.1前是HotSpot新生代收集的唯一选择
特点
- 年轻代
- 串行
- 复制算法
- 单线程收集
- Stop The World 进行垃圾收集时,必须暂停所有工作线程
应用场景
HotSpot在Client模式下默认的新生代收集器
参数
“-XX:+UseSerialGC”
Stop The World
JVM在后台自动发起和自动完成的,把用户正常的工作线程全部停掉,即GC停顿.
2.ParNew
ParNew垃圾收集器是Serial收集器的多线程版本。
特点
- 复制算法
- 多线程外,其余的行为、特点和Serial收集器一样;
- 如Serial收集器可用控制参数、收集算法、Stop The World、内存分配规则、回收策略等;
设置参数
- “-XX:+UseConcMarkSweepGC”:指定使用CMS后,会默认使用ParNew作为新生代收集器;
- “-XX:+UseParNewGC”:强制指定使用ParNew;
- “-XX:ParallelGCThreads”:指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同;
应用场景
在Server模式下,ParNew收集器是一个非常重要的收集器,因为除Serial外,目前只有它能与CMS收集器配合工作;
但在单个CPU环境中,不会比Serail收集器有更好的效果,因为存在线程交互开销。
为什么只有ParNew能与CMS收集器配合?
CMS是HotSpot在JDK1.5推出的第一款真正意义上的并发(Concurrent)收集器,第一次实现了让垃圾收集线程与用户线程(基本上)同时工作;
CMS作为老年代收集器,但却无法与JDK1.4已经存在的新生代收集器Parallel Scavenge配合工作;
因为Parallel Scavenge(以及G1)都没有使用传统的GC收集器代码框架,而另外独立实现;而其余几种收集器则共用了部分的框架代码;
3.Parallel Scavenge
Parallel Scavenge垃圾收集器因为与吞吐量关系密切,也称为吞吐量收集器(Throughput Collector)。
特点
- 新生代收集器
- 采用复制算法
- 多线程收集
参数
-
“-XX:MaxGCPauseMillis”
-
控制最大垃圾收集停顿时间,大于0的毫秒数;
-
MaxGCPauseMillis设置得稍小,停顿时间可能会缩短,但也可能会使得吞吐量下降;
因为可能导致垃圾收集发生得更频繁;
-
-
“-XX:GCTimeRatio”
- 设置垃圾收集时间占总时间的比率,0<n<100的整数;
- GCTimeRatio相当于设置吞吐量大小;
- 垃圾收集执行时间占应用程序执行时间的比例的计算方法是:
1 / (1 + n)
例如,选项-XX:GCTimeRatio=19,设置了垃圾收集时间占总时间的5%--1/(1+19);
默认值:1%--1/(1+99),即n=99;
老年代垃圾收集器
1.CMS
并发标记清理(Concurrent Mark Sweep,CMS)收集器也称为并发低停顿收集器(Concurrent Low Pause Collector)或低延迟(low-latency)垃圾收集器;
特点
- 针对老年代
- 多线程
- "标记-清除"算法(不进行压缩操作,产生内存碎片);
- 以获取最短回收停顿时间为目标;
- 并发收集、低停顿;
- 需要更多的内存
应用场景
与用户交互较多的场景;
希望系统停顿时间最短,注重服务的响应速度;
以给用户带来较好的体验;
如常见WEB、B/S系统的服务器上的应用;
参数
2.Serial Old(MSC)
Serial Old是 Serial收集器的老年代版本;
特点
- 单线程
- 针对老年代
- 采用"标记-整理"算法(压缩,Mark-Sweep-Compact)
应用场景
- 主要用于Client模式;
- 在Server模式有两大用途
- 1在JDK1.5及之前,与Parallel Scavenge收集器搭配使用(JDK1.6有Parallel Old收集器可搭配)
- 作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用
3.Parallel Old
Parallel Old垃圾收集器是Parallel Scavenge收集器的老年代版本;
JDK1.6 开始出现
特点
- 针对老年代
- 采用"标记-整理"算法
- 多线程收集
应用场景
注重高吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge+Parallel Old 收集器。
整堆收集器G1 (老年代年轻代都可以)
G1(Garbage-First)是JDK7-u4才推出商用的收集器;
特点
- 标记-清理 ,拷贝-复制
- 并行与并发
- 分代收集
- 空间整合
- 可预测的停顿
收集步骤
- 初始标记:仅标记GC Roots能直接到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象。(需要线程停顿,但耗时很短。)
- 并发标记:从GC Roots开始对堆中对象进行可达性分析,找出存活对象。(耗时较长,但可与用户程序并发执行)
- 最终标记:为了修正在并发标记期间因用户程序执行而导致标记产生变化的那一部分标记记录。且对象的变化记录在线程Remembered Set Logs里面,把Remembered Set Logs里面的数据合并到Remembered Set中。(需要线程停顿,但可并行执行。)
- 筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。(可并发执行)
判断存活有两种算法:
- 引用计数算法
给对象添加一个引用计数器,当有地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;计数器为0的对象就是不被使用的。 - 可达性分析算法
通过GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
minor GC 和 fullGC
minor GC
新生代(由 Eden and Survivor 组成)的垃圾收集叫做Minor GC
Major GC
Major GC 是清理老年代。
fullGC
当年老代满时会引发Full GC,Full GC将会同时回收年轻代、年老代