垃圾回收
GC算法
如何判断对象可以回收?
答案:
1. 引用计数法
- 对象被引用时计数+1,引用失效时计数-1
- 计数为0时可以回收
- 缺点:无法解决循环引用
java
// 循环引用
objA.instance = objB;
objB.instance = objA;
// 两个对象互相引用,计数永远不为02. 可达性分析算法(Java使用)
- 从GC Roots开始向下搜索
- 不可达的对象可以回收
GC Roots包括:
- 虚拟机栈中引用的对象
- 方法区中静态变量引用的对象
- 方法区中常量引用的对象
- 本地方法栈中引用的对象
- 活跃线程
垃圾回收算法有哪些?
答案:
1. 标记-清除(Mark-Sweep)
- 标记:标记所有需要回收的对象
- 清除:回收被标记的对象
优点:简单 缺点:产生内存碎片
2. 标记-复制(Mark-Copy)
- 将内存分为两块
- 将存活对象复制到另一块
- 清空原来的内存
优点:无内存碎片 缺点:浪费一半内存
新生代使用:Eden:Survivor0:Survivor1 = 8:1:1
3. 标记-整理(Mark-Compact)
- 标记:标记所有存活对象
- 整理:将存活对象移到一端
- 清除:清理边界外的内存
优点:无内存碎片 缺点:移动对象成本高
老年代使用
4. 分代收集
- 新生代:标记-复制
- 老年代:标记-清除或标记-整理
垃圾收集器
常见的垃圾收集器?
答案:
新生代收集器
├── Serial(串行)
├── ParNew(并行)
└── Parallel Scavenge(并行)
老年代收集器
├── Serial Old(串行)
├── Parallel Old(并行)
└── CMS(并发标记清除)
全堆收集器
├── G1(分区收集)
└── ZGC(低延迟)Serial收集器?
答案:
- 单线程收集器
- 收集时暂停所有工作线程(STW)
- 适用于客户端模式
bash
-XX:+UseSerialGCParNew收集器?
答案:
- Serial的多线程版本
- 新生代收集器
- 配合CMS使用
bash
-XX:+UseParNewGCParallel Scavenge收集器?
答案:
- 多线程收集器
- 关注吞吐量(运行用户代码时间 / 总时间)
- 适用于后台计算
bash
-XX:+UseParallelGC
-XX:MaxGCPauseMillis=100 # 最大停顿时间
-XX:GCTimeRatio=99 # 吞吐量CMS收集器?
答案: Concurrent Mark Sweep,并发标记清除,关注最短停顿时间。
工作流程:
1. 初始标记(STW)
- 标记GC Roots直接关联的对象
↓
2. 并发标记
- 从GC Roots遍历对象图
↓
3. 重新标记(STW)
- 修正并发标记期间变动的对象
↓
4. 并发清除
- 清除垃圾对象优点:
- 并发收集,停顿时间短
缺点:
- 占用CPU资源
- 无法处理浮动垃圾
- 产生内存碎片
bash
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=80 # 老年代使用80%时触发G1收集器?
答案: Garbage First,面向服务端的收集器,JDK9默认。
特点:
- 分区收集(Region)
- 可预测的停顿时间
- 整体标记-整理,局部标记-复制
Region:
- 将堆划分为多个大小相等的Region
- 每个Region可以是Eden、Survivor、Old、Humongous
工作流程:
1. 初始标记(STW)
2. 并发标记
3. 最终标记(STW)
4. 筛选回收(STW)
- 根据停顿时间目标,选择回收价值最大的Regionbash
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200 # 期望停顿时间
-XX:G1HeapRegionSize=1m # Region大小ZGC收集器?
答案: JDK11引入的低延迟收集器。
特点:
- 停顿时间不超过10ms
- 支持TB级堆
- 使用染色指针和读屏障
bash
-XX:+UseZGCGC类型
Minor GC、Major GC、Full GC的区别?
答案:
Minor GC(Young GC)
- 新生代GC
- 频繁触发,速度快
- Eden区满时触发
Major GC
- 老年代GC
- 通常伴随至少一次Minor GC
Full GC
- 整堆GC(新生代+老年代+方法区)
- 速度慢,尽量避免
触发Full GC的条件:
- 老年代空间不足
- 方法区空间不足
- System.gc()
- CMS GC失败
GC日志
如何查看GC日志?
答案:
bash
# JDK8
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:gc.log
# JDK9+
-Xlog:gc*:file=gc.log:time,level,tags日志示例:
[GC (Allocation Failure) [PSYoungGen: 2048K->512K(2560K)] 2048K->720K(9728K), 0.0012345 secs]
解释:
- GC类型:Minor GC
- 原因:分配失败
- 收集器:PSYoungGen(Parallel Scavenge)
- 新生代:2048K->512K(回收前->回收后)
- 新生代总大小:2560K
- 整堆:2048K->720K
- 整堆总大小:9728K
- 耗时:0.0012345秒练习题
- 什么时候会触发Full GC?如何避免?
- CMS和G1的区别?
- 如何选择垃圾收集器?
- 如何分析GC日志?