核心是用WeakReference替代强引用以切断隐式引用链,如用WeakHashMap替代静态HashMap、静态内部类替代非静态内部类、ThreadLocal后调用remove()、监听器及时解绑等,而非依赖其自动清理。

在 Java 类中使用弱引用防止内存泄漏,核心是用 WeakReference 替代强引用,让对象在无其他强引用时能被 GC 及时回收。这不是“加个 WeakReference 就完事”,而是要结合场景切断不该存在的引用链。
缓存类优先用 WeakHashMap 或 WeakReference 包装值
普通 HashMap 静态持有对象会阻止回收;WeakHashMap 的 key 是弱引用,当 key 对象不可达时,整条 entry 会被自动清理。适合键本身生命周期短、且不需长期保有的缓存场景(如 UI 组件与数据的临时映射)。
- 直接用
WeakHashMap<Key, Value>:key 被回收后,对应 entry 在下一次哈希表操作(如 get/put)时惰性清理 - 手动包装 value:若需更细粒度控制(比如 key 不能弱化,但 value 可丢),可用
Map<Key, WeakReference<Value>>,读取前检查ref.get() != null - 避免把 WeakReference 存进静态集合后忘记清理——它只是“允许回收”,不等于“自动清理引用容器”
内部类场景改用静态 + 显式传参
非静态内部类隐式持外部类引用,若该内部类实例被线程、监听器、缓存等长期持有,就会拖住整个外部类实例。
- 把内部类声明为
static,彻底断开对外部类的隐式引用 - 如需访问外部类数据,通过构造方法或方法参数显式传入所需字段(而非整个 this)
- 匿名内部类同理:优先用 Lambda(无隐式引用),或改写为静态私有类
ThreadLocal 使用后必须 remove()
ThreadLocal 的 key 是弱引用,但 value 是强引用。若线程复用(如线程池),而没调用 remove(),value 会一直留在 ThreadLocalMap 中,造成泄漏。
立即学习“Java免费学习笔记(深入)”;
- 每次用完务必调用
threadLocal.remove(),尤其在 finally 块或 try-with-resources 的 close 逻辑中 - 不要依赖 “置 threadLocal 变量为 null” 来清理——这只是断开了局部变量引用,ThreadLocalMap 中的 value 仍在
- 若 value 是大对象(如 byte[]、List),泄漏代价明显,必须主动清理
监听器和回调注册后记得解绑
长生命周期对象(如 Activity、Service、单例)注册了短生命周期对象(如 Fragment、Adapter)的监听器,却不取消,会导致后者无法释放。
- 在短生命周期对象销毁时(如 onDestroy、onDetachedFromWindow),显式调用
xxx.removeXXXListener(...) - 考虑用 WeakReference 包装监听器本身(如自定义事件总线),但注意这仅缓解,不能替代解绑逻辑
- Android 开发中可借助 LifecycleOwner 自动绑定/解绑,减少手动管理遗漏


















