概念
- 什么是垃圾?
- 垃圾是指在
运行程序中没有任何指针指向的对象
- 如果不及时对内存中的垃圾进行清理,那垃圾对象所占用的空间会
一直保留到应用程序结束
,被保留的空间无法被其它对象使用。甚至可能会导致内存溢出
- 垃圾是指在
- 为什么需要GC?
内存会被消耗完
- 垃圾回收不仅可以释放没用的对象,也可清除内存里的记录碎片。碎片整理将所占用的堆内存移到堆的一端,以便
JVM将整理出的内存分配给新的对象
没有GC就不能保证应用程序的正常运行
。而经常造成STW的GC又跟不上实际的需求,所以需要不断优化
- GC的作用区域
一、回收算法
1. 垃圾标记阶段:对象存活判断
对象实例存放在堆中,在GC执行垃圾回收之前,首先需要区分出内存存活/死亡的对象。GC在垃圾回收时,会将标记为已经死亡的对象所占用的内存空间释放掉。
- 判断对象存活一般有两种方式:引用计数法和可达性分析法
1.1 引用计数法
对每个对象保存一个整型的引用计数器属性,用于记录对象被引用的情况。因为存在循环引用的情况,所以Java不采用这种标记方式
- 对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。当对象A的引用计数器的值为0时,即表示对象A不可能再被使用,可进行回收
- 优点:实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性
- 缺点:增加了存储空间的开销(需要单独的字段存储计数器),时间开销(每次赋值都需要更新计数器,±法),
无法处理循环引用的情况
1. 2 可达性分析算法
解决了在引用计数算法中循环引用问题,防止内存泄漏的发生
CMS:标记出能直接关联
的对象时会发生STW
1.3 对象的finalization机制
1.4 两次标记
判断一个对象是否可回收,至少要经历两次标记过程
2. 垃圾清除阶段
标记-清除算法(Mark-Sweep)、复制算法(Copying)、标记-压缩算法(Mark-Compact)
2.1 标记-清除
- 算法效率低,GC后产生内存碎片
2.2 复制算法
建立在存活对象 对象少、垃圾对象多的前提下
是年轻代使用的清除算法,不适用老年代,因为老年代要移动的对象太多,算法的性能较低
- 复制算法适用于新生代,一次通常可以回收70%-80%的内存空间,回收性价比很高。所以现在的商业虚拟机都是用这种算法回收新生代。
2.3 标记-压缩(整理)算法
适用于老年代的垃圾回收算法,存活对象较多
3.回收机制
3.1 分代收集算法
主流算法:不同生命周期的对象采用不同的收集方式
3.2 增量收集算法(时间上优化)
代表:CMS、G1
3.3 分区算法(空间上优化)
代表:G1
3.4 总结
- 增量收集算法:允许垃圾收集线程以
分阶段
的方式完成标记、清理、复制工作(并发) - 分区算法:将整个大的
内存区域(堆空间)分割
成多个小块,每次回收若干个 - 分代算法:按对象的生命周期划分内存区域
二、垃圾回收器
1. 分类
1.1 按线程分:串行/并行垃圾回收器
- 都会产生STW
1.2 按工作模式分:并发/独占式垃圾回收器
并发:一个时间段内,宏观上看GC和应用程序同时执行
1.3 按碎片处理方式分:压缩/非压缩
2. 评估GC的性能指标
吞吐量和暂停时间,在最大吞吐量优先的情况下,降低停顿时间。
- 吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)
- 暂停时间:一个时间段内应用程序被线程暂停,让GC线程执行的状态。
三、垃圾回收器
7款经典收集器
针对不同的场景,提供不同的垃圾收集器(移动端,服务端等)
1.1 Serial回收器:串行回收
1.2 ParNew回收器:并行回收
是 Serial GC(年轻代中的单线程GC) 的多线程版本
机制:复制算法,并行回收,STW
1.3 Parallel回收器:吞吐量优先
复制算法(年轻代)、并行回收、STW、可控制吞吐量、自适应调节策略
Java8,默认的垃圾收集器:
Parallel Scavenge
和Parallel Old
,在Server(注重高并发,整体的吞吐量)模式下的内存回收性能不错
Parallel Scavenge区别于parNew的地方在于可以控制垃圾收集的停顿时间(暂停时间)、垃圾收集的时间比值(吞吐量)以及自适应策略等
1.4 CMS回收器:低延迟
CMS 只能与 ParNew/Serial 配合使用
1.4.1 CMS工作原理
1.4.2 CMS回收器:低延时
1.4.3 CMS:优缺点
1.4.4 CMS:优缺点
- CMS:
- JDK9中标注CMS过期,之后将被废弃;JDK14中删除
1.5 G1(Garbage-First):区域分代化
低时延优先,即在限定的时间范围内,优先收集价值更大的Region,从而达到尽可能高的吞吐量
JDK 9以后的默认垃圾收集器
- 由于侧重点在于回收垃圾最大量的区间(Region),所以叫垃圾优先
- 命令行查看JDK8中POld默认的垃圾会收集(PS+POld)
1.5.1 G1 : 优点
1.5.2 G1 : 缺点
小内存应用上表现不好
1.5.3 G1 : 常见步骤、应用场景
1.5.4 G1 回收器垃圾回收过程
- 年轻代GC,(年轻代移动存活对象到Survivor区间或者老年区间)->STW、并行)
- 年轻代GC+老年代并发标记,达到阈值,默认45%
- 混合回收,年轻代全部回收+老年代回收若干Region,老年区间移动存活对象到空闲区,空闲区也成为老年代的一部分
面试:GC垃圾回收流程
- 并发标记结束后,老年代百分百为垃圾的内存分段被回收了
1.6 总结
+JDK14:弃用 JDK 8中 默认的垃圾回收器:PS+POld;删除CMS垃圾回收器