这不是真正的内存泄露,而是因引用未及时断开导致的假性泄露;静态集合、单例持有强引用、非静态内部类隐式引用及资源未关闭是四大主因,需分别通过清理机制、弱引用、静态化+weakreference、显式close等手段精准治理。

这不是真正的内存泄露,而是被误判为泄露的典型场景——本质是引用关系没及时断开,让垃圾回收器“以为”对象还在用。
静态集合类是最常见的诱因
比如用 static HashMap
- 解决办法不是不用静态集合,而是加清理机制:按时间(TTL)、按访问频次(LRU)、或显式调用 remove
- 若只是临时暂存,优先用 ThreadLocal 或方法作用域内的局部变量,避免升级为静态引用
- 使用 WeakHashMap 替代普通 HashMap,当 key 对象仅被 WeakHashMap 引用时,GC 可正常回收
单例与监听器也容易“卡住”对象
单例对象天然长生命周期。如果它持有了 Activity、Fragment、View 或回调接口的强引用(比如注册了未解绑的监听器),这些短命对象就会被拖着无法释放。Android 中因此导致的 OOM 很常见。
- 注册监听器后,务必在对应生命周期结束时 unregister(如 onDestroy、onDestroyView)
- 对可能短命的对象,改用弱引用包装:WeakReference
、WeakReference - 非静态内部类(如 Handler、AsyncTask 匿名子类)默认持有外部类引用,应改为静态内部类 + WeakReference
连接类资源不 close 是硬性泄漏
Connection、Statement、ResultSet、InputStream、Socket 等,底层通常关联本地资源(文件句柄、socket 描述符)。JVM 的 finalize 方法虽可能兜底关闭,但时机不可控、效率低,极易引发句柄耗尽或堆外内存堆积。
- 必须显式调用 close(),且放在 finally 块或 try-with-resources 中
- 自定义资源类要实现 AutoCloseable,并确保 close() 幂等、可重入
- 数据库连接池(如 HikariCP)能缓解问题,但不能替代代码层的正确释放逻辑
作用域与置 null 的实际价值有限
很多人习惯在方法末尾写 obj = null,认为这能帮 GC。其实对局部变量几乎无用——方法栈帧弹出后,引用自然消失。真正起作用的是:防止对象被意外提升为成员变量、或被闭包/匿名类捕获。
- 重点不在“设 null”,而在“别让引用逃逸出该销毁的范围”
- 成员变量用完后置 null 有意义,尤其是大对象(如 byte[]、Bitmap)或集合类
- 更可靠的做法是缩小变量作用域:在 if 块内声明,而不是提前提前定义在方法开头










