Java内存泄漏本质是“该回收的对象因被意外持有而无法释放”,导致内存持续增长、GC频繁、最终OOM;关键在监控对象生命周期,典型场景包括静态集合、未关闭资源、ThreadLocal误用、内部类隐式引用等。

Java内存泄漏不是“内存用得多”,而是“该回收的没回收,越积越多”。它不会立刻报错,但会让服务越跑越慢、GC越来越频繁,最终OOM崩溃。识别和预防的关键,在于盯住对象生命周期是否与预期一致。
静态集合类持有对象引用
静态变量生命周期与类相同,只要类不卸载,它持有的对象就无法被GC回收。常见于缓存、监听器注册表、单例管理器等场景。
- 比如用
static Map<string object></string>缓存用户会话,但忘记在用户登出时移除对应条目 - 又如注册了事件监听器却未在销毁时反注册,导致整个Activity或Service实例被长期持有着
- 解决办法:优先使用弱引用容器(
WeakHashMap)、设置过期策略(如Guava Cache)、或显式清理逻辑
未关闭的资源与非托管句柄
Java中很多资源(数据库连接、文件流、网络Socket、SDK句柄)背后关联着堆外内存或操作系统资源。JVM GC只管堆内对象,不管这些“外面的东西”。
- 典型表现:堆内存不高,但进程总内存持续上涨;
top看RES很高,jstat却显示老年代稳定 - 海康SDK中
m_lRealHandle、m_lUserID未调用NET_DVR_StopRealPlay/NET_DVR_Logout - 数据库连接未在
finally块或try-with-resources中关闭,导致连接池耗尽、底层Socket堆积 - 解决办法:所有资源操作必须走
try-with-resources;自定义资源类实现AutoCloseable;对非托管句柄封装为SafeResource implements Disposable
ThreadLocal 使用不当
ThreadLocal本身不是泄漏源,但它的值若为强引用且线程长期存活(如线程池中的工作线程),就会造成“线程→ThreadLocalMap→Entry→value”的强引用链,使value及其依赖对象无法回收。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
立即学习“Java免费学习笔记(深入)”;
- 尤其危险的是value为大对象(如缓存Map、上下文容器)或含外部引用时
- 常见误写:
threadLocal.set(new BigObject())后未调用remove() - 正确姿势:在业务逻辑结束时明确
threadLocal.remove();避免在ThreadLocal中存可变大对象;必要时用WeakReference<t></t>包装value
内部类/匿名类隐式持有所属实例
非静态内部类默认持有外部类的this引用。若该内部类对象被长期持有(如注册为回调、放入静态集合、作为任务提交到线程池),外部类实例也会被一并锁死。
- 例如:在Activity中创建Handler或Runnable并post延迟任务,Activity已finish,但Handler仍持有其引用,导致内存无法释放
- 解决方案:使用静态内部类 + WeakReference;或改用
Handler(Looper.getMainLooper())配合弱引用上下文 - Lambda表达式在捕获
this或实例字段时,同样存在该问题,需留意作用域
监控与定位不能只看堆内存
靠free -h或jstat -gc看到堆正常,不代表没泄漏。真正的泄漏可能藏在:
- 堆外内存:Direct Buffer、JNI分配、MappedByteBuffer——用
jcmd <pid> VM.native_memory summary</pid>查 - 元空间(Metaspace):动态生成类过多(如CGLIB代理、JSON反序列化大量新类型)
- 线程数持续增长:每个线程栈+ThreadLocalMap都占内存,
ps -eL | grep <pid> | wc -l</pid>辅助判断 - 推荐组合:OSHI实时监控+JVM启动参数
-XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError+MAT分析堆转储

















