全文共 2195 个字,读完大约需要 8 分钟。
如果垃圾回收的算法属于内存回收的方法论的话,那本文讨论的垃圾回收器就属于内存回收的具体实现。
因为不同的厂商(IBM、Oracle),实现的垃圾回收器各不相同,而本文要讨论的是 Oracle 的 HotSpot 虚拟机所使用的垃圾回收器。
常用垃圾回收器,如下图所示:
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
其中相互连线的垃圾回收器,表示可以相互搭配使用。
新生代 And 老生代目前常用的商用垃圾收集器都使用的是分代垃圾回收方式。
分代垃圾回收器把内存分为:新生代(Young Generation)和老生代(Tenured Generation),如下图所示:
(图片来自fancydeepin)
默认情况下,新生代和老生代的内存比例是 1:2,该值可以通过 -XX:NewRatio 来设定。
新生代(Young Generation)程序中的大部分对象都符合“朝生夕死”的特性,所以绝大数新创建的对象都会存放在新生代,除非是大对象会直接进入老生代。新生代采用的是复制算法,这样可以更高效的回收内存空间。
新生代有细分为:Eden、Form Survivor、To Survivor 三个区域,默认的比例是 8:1:1,可以通过 -XX:SurvivorRatio 来设定。
新生代垃圾回收的执行过程:
1、Eden 区 + From Survivor 区存活着的对象复制到 To Survivor 区;
2、清空 Eden 和 From Survivor 分区;
3、From Survivor 和 To Survivor 分区交换(From 变 To,To 变 From)。
老生代(Tenured Generation)老生代垃圾回收的频率比新生代低,存放的主要对象是:
1、新生代对象经过 N 次 GC 晋升到老年代。
可以通过设置 -XX:MaxTenuringThreshold=5 来设置,默认值是 15 次。
2、大对象直接存储到老生代。
所谓的“大对象”指的是需要连续存储空间的对象,比如:数组。
当大对象在新生代存储不下的时候,就需要分配担保机制,把当前新生代的所有对象复制到老年代中,因为分配担保机制需要涉及大量的复制,会导致性能问题,所有最好的方案是直接把大对象存储到老生代中。
通过参数 -xx:PretrnureSizeThreshold 来设定大对象的值。
注意:该参数只有 Serial 和 ParNew 垃圾回收器有效。
SerialSerial 最早的垃圾回收器,JDK 1.3.1 之前新生代唯一的垃圾回收器,使用的是单线程串行回收方式,在单 CPU 环境下性能较好,因为单线程执行不存在线程切换。
线程类型: 单线程
使用算法: 复制算法
指定收集器: -XX:+UseSerialGC
Serial OldSerial 收集器的老年代版本,同样也是单线程的。它有一个实用的用途作为CMS收集器的备选预案,后面介绍CMS的时候会详细介绍。
线程类型: 单线程
使用算法: 标记-整理
指定收集器: -XX:+UseSerialGC
ParNewParNew 其实就是 Serial 的多线程版本,可以和 Serial 共用很多控制参数,比如:-XX:SurvivorRatio , ParNew 可以和 CMS 配合使用。
(注:图片来源于零壹技术栈)
线程类型: 多线程
使用算法: 复制
指定收集器: -XX:+UseParNewGC
Parallel ScavengeParallel 和 ParNew 收集器类似,也是多线程的,但 Parallel 是吞吐量优先的收集器,GC停顿时间的缩短是以吞吐量为代价的,比如收集 100MB 的内存,需要 10S 的时间,CMS 则会缩短为 7S 收集 50 MB 的内存,这样停顿的时间确实缩少了,但收集的频率变大了,吞吐量就变小了。
线程类型: 多线程
使用算法: 复制
指定收集器: -XX:+UseParallelGC
Parallel OldParallel Old 是 Parallel 的老生代版本,同样是吞吐量优先的收集器。
线程类型: 多线程
使用算法: 标记-整理
指定收集器: -XX:+UseParallelOldGC
CMSCMS(Concurrent Mark Sweep)一种以获得最短停顿时间为目标的收集器,非常适用B/S系统。
使用 Serial Old 整理内存。
CMS 运行过程:
(注:图片来源于零壹技术栈)
1、初始标记
标记 GC Roots 直接关联的对象,需要 Stop The World 。
2、并发标记
从 GC Roots 开始对堆进行可达性分析,找出活对象。
3、重新标记