一、垃圾回收基础概念
1. 什么是垃圾回收
垃圾回收(Garbage Collection, GC)是JVM自动管理内存的机制,主要负责:
-
分配内存
-
确保被引用的对象保持在内存中
-
回收不再被引用的对象占用的内存
2. 需要回收的内存区域
-
堆内存(Heap):主要回收区域,存放对象实例
-
方法区(Metaspace):回收废弃常量和无用的类
二、判断对象可回收的算法
1. 引用计数法(已淘汰)
-
每个对象维护一个引用计数器
-
当引用为0时立即回收
-
缺点:无法解决循环引用问题
2. 可达性分析算法(主流)
通过"GC Roots"对象作为起点,向下搜索引用链:
-
GC Roots包括:
-
虚拟机栈中引用的对象
-
方法区静态属性引用的对象
-
方法区常量引用的对象
-
Native方法引用的对象
-
同步锁持有的对象
-
三、垃圾回收算法
1. 标记-清除(Mark-Sweep)
-
步骤:
-
标记所有需要回收的对象
-
统一回收被标记对象
-
-
缺点:
-
效率问题(标记和清除效率都不高)
-
空间问题(产生内存碎片)
-
2. 标记-整理(Mark-Compact)
-
步骤:
-
标记所有需要回收的对象
-
让所有存活对象向一端移动
-
清理边界以外的内存
-
-
优点:避免内存碎片
-
缺点:移动对象成本高
3. 复制算法(Copying)
-
原理:
-
内存分为大小相同的两块
-
每次只使用其中一块
-
存活对象复制到另一块,然后清理已使用块
-
-
优点:高效无碎片
-
缺点:内存利用率仅50%
4. 分代收集理论(Generational Collection)
-
新生代(Young Generation):
-
特点:对象朝生夕死(98%对象存活时间很短)
-
算法:复制算法(Eden:Survivor=8:1:1)
-
-
老年代(Tenured Generation):
-
特点:存活对象较多
-
算法:标记-清除或标记-整理
-
四、垃圾收集器实现
1. 新生代收集器
收集器 | 算法 | 特点 |
---|---|---|
Serial | 复制 | 单线程,Client模式默认 |
ParNew | 复制 | Serial的多线程版本 |
Parallel Scavenge | 复制 | 吞吐量优先 |
2. 老年代收集器
收集器 | 算法 | 特点 |
---|---|---|
Serial Old | 标记-整理 | Serial的老年代版 |
Parallel Old | 标记-整理 | Parallel Scavenge的老年代版 |
CMS | 标记-清除 | 低延迟,并发收集 |
3. 全堆收集器
收集器 | 算法 | 特点 |
---|---|---|
G1 | 标记-整理+分区 | 可预测停顿,JDK9+默认 |
ZGC | 着色指针+读屏障 | 超低延迟(<10ms) |
五、内存分配与回收策略
1. 对象优先在Eden分配
-
新生代内存布局:
┌─────────┬───────┬───────┐ │ Eden │ S0 │ S1 │ └─────────┴───────┴───────┘
-
当Eden区满时触发Minor GC
2. 大对象直接进老年代
-
通过
-XX:PretenureSizeThreshold
设置阈值 -
避免在Eden和Survivor之间大量复制
3. 长期存活对象进老年代
-
对象年龄计数器(Survivor中每熬过1次GC年龄+1)
-
-XX:MaxTenuringThreshold
设置晋升阈值(默认15)
六、GC日志分析
1. 典型GC日志
[GC (Allocation Failure) [PSYoungGen: 65536K->10720K(76288K)] 65536K->15011K(251392K), 0.0090413 secs] [Times: user=0.02 sys=0.01, real=0.01 secs]
-
PSYoungGen
:Parallel Scavenge收集器 -
65536K->10720K
:回收前->回收后大小 -
0.0090413 secs
:耗时
2. 重要JVM参数
参数 | 作用 |
---|---|
-Xms/-Xmx | 初始/最大堆大小 |
-XX:NewRatio | 老年代与新生代比例 |
-XX:SurvivorRatio | Eden与Survivor区比例 |
-XX:+PrintGCDetails | 打印GC详细信息 |
-XX:+UseG1GC | 使用G1收集器 |