1. System.gc()的理解 #
工作机制图解 #
核心要点 #
- 非强制调用:
<font style="background-color:rgb(252, 252, 252);">System.gc()</font>
本质是<font style="background-color:rgb(252, 252, 252);">Runtime.getRuntime().gc()</font>
的封装,只是建议而非强制 - 执行不确定性:
- 可能触发Full GC(YoungGC+OldGC+MetaspaceGC)
- 具体行为取决于
<font style="background-color:rgb(252, 252, 252);">-XX:+ExplicitGCInvokesConcurrent</font>
参数
- 生产环境禁用建议:
-XX:+DisableExplicitGC # 禁止显式GC调用
-XX:+ExplicitGCInvokesConcurrent # 使用并发方式执行
2. 内存溢出与内存泄露 #
内存溢出(OOM)图解 #
常见OOM类型 #
- Heap OOM:
<font style="background-color:rgb(252, 252, 252);">Java heap space</font>
- Metaspace OOM:
<font style="background-color:rgb(252, 252, 252);">Metaspace</font>
- 栈OOM:
<font style="background-color:rgb(252, 252, 252);">Requested stack size exceeded</font>
- 直接内存OOM:
<font style="background-color:rgb(252, 252, 252);">Direct buffer memory</font>
内存泄漏(Memory Leak)案例 #
public class MemoryLeak {
static List<Object> list = new ArrayList<>();
public void addData() {
for(int i=0; i<1000; i++){
list.add(new byte[1024 * 1024]); // 持续添加大对象
}
}
}
泄漏特征 #
- 对象不再使用但仍被GC Roots引用
- 常见泄漏场景:
- 静态集合类
- 未关闭的资源(数据库连接、文件流)
- 监听器未注销
3. Stop The World #
STW发生机制图解 #
关键影响与优化 #
- 暂停时间指标:
- CMS:
<font style="background-color:rgb(252, 252, 252);">-XX:MaxGCPauseMillis=200</font>
(默认200ms) - G1:
<font style="background-color:rgb(252, 252, 252);">-XX:MaxGCPauseMillis=200</font>
- CMS:
- 优化策略:
-XX:+UseParallelGC # 并行回收缩短STW
-XX:+UseConcMarkSweepGC # CMS并发标记
-XX:+UseG1GC # G1的可预测暂停
4. 垃圾回收的并行与并发 #
概念对比图解 #
技术实现细节 #
- 并行(Parallel):
- <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(252, 252, 252);">典型场景:</font>`<font style="background-color:rgb(252, 252, 252);">-XX:+UseParallelGC</font>`<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(252, 252, 252);">(ParNew/Parallel Scavenge)</font>
- 并发(Concurrent):
- <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(252, 252, 252);">典型场景:CMS的并发标记阶段</font>
5. 安全点与安全区域 #
安全点(Safepoint)机制 #
主动式中断实现 #
// HotSpot虚拟机源码片段
void SafepointSynchronize::block_jni_calls() {
while (true) {
if (SafepointSynchronize::is_synchronized() break;
os::naked_short_sleep(1); // 自旋等待
}
}
安全区域(Safe Region) #
6. 再谈引用:强引用 #
强引用生命周期 #
典型代码示例 #
Object obj = new Object(); // 强引用
obj = null; // 断开引用后对象可被回收
强引用与内存泄漏 #
7. 再谈引用:软引用 #
回收机制图解 #
典型使用场景 #
// 创建软引用对象
SoftReference<byte[]> softRef = new SoftReference<>(new byte[10 * 1024 * 1024]);
// 获取对象(可能返回null)
byte[] data = softRef.get();
if(data == null) {
// 重新加载数据
}
参数调优 #
-XX:SoftRefLRUPolicyMSPerMB=1000 # 每MB空闲内存保留软引用1秒
8. 再谈引用:弱引用 #
生命周期图解 #
WeakHashMap应用 #
WeakHashMap<Key, Value> cache = new WeakHashMap<>();
Key key = new Key();
cache.put(key, new Value();
key = null; // 下次GC时自动清理条目
9. 再谈引用:虚引用 #
对象跟踪机制 #
典型应用场景 #
// 创建虚引用(必须关联引用队列)
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), queue);
// 监控对象回收(常用于堆外内存管理)
while(true) {
Reference<?> ref = queue.remove();
// 执行内存回收后续操作
}
10. 终结器引用 #
finalize()执行流程 #
代码警示案例 #
public class Zombie {
static Zombie saved;
@Override
protected void finalize() {
saved = this; // 对象复活
}
}
11. 常见问题与解决方案 #
内存泄漏排查工具链 #
MAT分析步骤 #
- 生成堆转储文件
jmap -dump:format=b,file=heap.bin <pid>
- 查看支配树(Dominator Tree)
- 分析对象引用链
12. 高频面试问题与解答 #
问题1:System.gc()一定会触发GC吗? #
答:不一定。取决于JVM实现和运行参数,使用<font style="background-color:rgb(252, 252, 252);">-XX:+DisableExplicitGC</font>
会完全禁用该调用。
问题2:内存泄漏和内存溢出的区别? #
答:
- 内存泄漏:对象不再使用但无法回收(长期积累导致OOM)
- 内存溢出:当前内存空间无法满足分配需求(可能瞬时发生)
问题3:如何减少STW时间? #
答:
- 使用G1/CMS等低延迟收集器
- 调整堆大小:
<font style="background-color:rgb(252, 252, 252);">-Xmx4g -Xms4g</font>
- 控制年轻代比例:
<font style="background-color:rgb(252, 252, 252);">-XX:NewRatio=2</font>
问题4:弱引用和软引用的核心区别? #
答:
- 软引用:内存不足时回收(适合缓存)
- 弱引用:发现即回收(适合辅助数据结构)
问题5:安全点如何影响GC性能? #
答:
- 安全点过少 → STW等待时间增加
- 安全点过多 → 运行时性能损耗
- 优化方向:
<font style="background-color:rgb(252, 252, 252);">-XX:GuaranteedSafepointInterval=30000</font>