13.7、场景6 内存泄漏
场景 6:内存泄漏
欢迎回到第 13 章的学习。在上一节,我们学习了微服务调用失败的排查方法。现在我们要学习场景 6:内存泄漏。
本节将学习:内存 Metrics 异常、分析内存使用 Trace、查看内存相关 Logs、识别泄漏源头、以及内存优化。
内存 Metrics 异常
内存 Metrics 异常的作用是什么? 通过 Metrics 发现内存使用异常,确认内存泄漏问题。
如何查看内存 Metrics? 查看以下指标:
- 内存使用率
- 内存增长趋势
- GC 频率和时间
- 堆内存使用情况
异常指标示例:
- 内存使用率持续上升
- GC 频率增加但效果不明显
- 堆内存使用接近上限
内存 Metrics 查询:
# 内存使用率 100 * (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) # JVM 堆内存使用率 jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} * 100 # GC 频率 rate(jvm_gc_collection_seconds_count[5m]) # GC 时间 rate(jvm_gc_collection_seconds_sum[5m])
分析内存使用 Trace
分析内存使用 Trace 的作用是什么? 使用 Trace 分析内存使用的模式,识别内存泄漏的触发点。
如何分析内存使用 Trace? 查看内存相关的 Trace,分析:
- 内存分配的时机
- 内存释放的时机
- 内存使用模式
内存使用模式分析:
查看内存相关 Logs
查看内存相关 Logs 的作用是什么? 通过 Logs 分析内存相关的详细信息,找到内存泄漏的原因。
如何查看内存相关 Logs? 使用 LogQL 查询内存相关日志:
LogQL 查询示例:
# 查询 GC 日志 {level="info"} && {message=~".*GC.*"} # 查询 OOM 错误日志 {level="error"} && {message=~".*OutOfMemoryError.*"} # 查询内存警告日志 {level="warn"} && {message=~".*memory.*"}
识别泄漏源头
识别泄漏源头的作用是什么? 找到内存泄漏的具体源头,定位问题代码。
如何识别泄漏源头? 分析内存使用模式,识别:
- 未释放的资源
- 循环引用
- 缓存未清理
- 监听器未移除
常见内存泄漏原因:
// 1. Unclosed resources public void processFile() { FileInputStream fis = new FileInputStream("file.txt"); // Forgot to turn off fis } // 2. Cyclic references class A { B b; } class B { A a; // Cyclic references } // 3. The cache has not been cleaned private Map<String, Object> cache = new HashMap<>(); // The cache continues to grow and has not been cleaned // 4. The listener has not been removed eventBus.addListener(listener); // Forgot to remove the listener
内存优化
内存优化的作用是什么? 根据分析结果,实施内存优化方案,解决内存泄漏问题。
优化方案包括哪些呢?
第一个:修复内存泄漏。 修复代码中的内存泄漏问题。
第二个:优化内存使用。 优化内存使用模式,减少内存占用。
第三个:调整 GC 参数。 调整垃圾回收参数,优化 GC 性能。
第四个:增加内存限制。 增加应用内存限制,暂时缓解问题。
内存优化示例:
// Fix: Use try-with-resources public void processFile() { try (FileInputStream fis = new FileInputStream("file.txt")) { // Using file streams } // Auto shut off } // Fix: Using weak references private Map<String, WeakReference<Object>> cache = new HashMap<>(); // Fix: remove the listener @Override public void destroy() { eventBus.removeListener(listener); } // JVM GC Parameter optimization -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m
本节小结
在本节中,我们学习了场景 6:内存泄漏:
第一个是内存 Metrics 异常。 通过 Metrics 发现内存使用异常,确认内存泄漏问题。
第二个是分析内存使用 Trace。 使用 Trace 分析内存使用的模式,识别内存泄漏的触发点。
第三个是查看内存相关 Logs。 通过 Logs 分析内存相关的详细信息,找到内存泄漏的原因。
第四个是识别泄漏源头。 找到内存泄漏的具体源头,定位问题代码。
第五个是内存优化。 根据分析结果,实施内存优化方案,解决内存泄漏问题。
故障排查流程: 内存 Metrics 异常 → 分析内存使用 Trace → 查看内存相关 Logs → 识别泄漏源头 → 实施内存优化 → 验证修复效果。
这就是场景 6:内存泄漏。通过场景 6 的学习,我们掌握了内存泄漏的排查方法。
在下一节,我们将学习场景 7:缓存命中率低。学习如何排查缓存问题。