内存泄漏排查和解决
内存泄漏是Java开发中常见的问题,掌握排查和解决方法对于系统稳定性至关重要。
核心问题
什么是内存泄漏?
内存泄漏是指程序在运行过程中,不再使用的对象无法被垃圾回收器回收,导致内存占用持续增长。
常见的内存泄漏场景
未关闭的资源
- 文件流未关闭
- 数据库连接未关闭
- 网络连接未关闭
集合引用
- 集合中持有大对象的引用
- 监听器未移除
- 缓存未清理
内部类持有外部类引用
- 匿名内部类
- 非静态内部类
ThreadLocal未清理
- ThreadLocal使用后未remove
- 线程池中ThreadLocal的泄漏
排查方法
1. 使用jmap导出堆转储
bash
# 导出堆转储
jmap -dump:format=b,file=heap.hprof <pid>
# 查看堆内存使用情况
jmap -heap <pid>2. 使用MAT分析内存
- 打开堆转储文件
- 分析内存占用
- 查找内存泄漏点
3. 使用jstat监控GC
bash
# 查看GC情况
jstat -gc <pid> 1000
# 查看堆内存使用
jstat -gccapacity <pid>预防措施
使用try-with-resources
javatry (FileInputStream fis = new FileInputStream(file)) { // 使用资源 } // 自动关闭及时清理集合
javalist.clear(); map.clear();移除监听器
javaeventSource.removeListener(listener);ThreadLocal使用后清理
javatry { threadLocal.set(value); // 使用 } finally { threadLocal.remove(); }
常见面试题
如何判断是否存在内存泄漏?
- 监控堆内存使用情况
- 观察GC频率和耗时
- 使用内存分析工具
内存泄漏和内存溢出的区别?
- 内存泄漏:对象无法回收,内存占用持续增长
- 内存溢出:内存不足,无法分配新对象
如何避免内存泄漏?
- 及时关闭资源
- 清理集合和缓存
- 正确使用ThreadLocal