最有效的内存泄漏预防方式是将非静态内部类改为静态内部类并显式传参。需避免隐式持有外部类引用,对Activity等短生命周期对象使用WeakReference,并通过堆分析工具验证this$0引用链。

直接用静态内部类替代非静态内部类,是最简单也最有效的解决方式。只要内部类不访问外部类的非静态成员,就完全没必要保留这个隐式引用。
优先改造成静态内部类 + 显式传参
非静态内部类编译后会自带 this$0 字段,强引用着外部实例。改成 static 后,这个字段就没了,内部类变成真正独立的对象。
- 把
class Inner implements Runnable改成static class Inner implements Runnable - 如果需要访问外部状态(比如 Context、回调接口),通过构造方法显式传入,而不是依赖隐式 this
- 传入的参数若涉及 Activity 或 Fragment,建议包装成
WeakReference,避免强引用拖住 UI 组件
避免在短生命周期对象里提交非静态 Runnable 到长期线程池
Activity 创建一个匿名 Runnable 并 submit 给全局线程池,等于把 Activity “钉”在线程池的任务队列里——哪怕 Activity 已 finish,它仍被持有。
- 不要在 Activity/Fragment 的 onCreate 或 onResume 中直接 new Thread(runnable) 或 executor.submit(new Runnable(){...})
- 改用 lifecycleScope(Kotlin)或 LifecycleObserver(Java)绑定异步任务生命周期
- 若必须用线程池,确保 Runnable 是静态的,或使用 WeakReference 包裹关键引用
用工具确认是否真有 this$0 引用链
光靠代码检查容易漏,得看堆里实际引用关系。
立即学习“Java免费学习笔记(深入)”;
- 用
jmap -dump:format=b,file=heap.hprof <pid>抓取堆快照 - 用 VisualVM 或 Eclipse MAT 打开,对疑似泄漏的外层类(如 MyActivity)执行 “Merge Shortest Paths to GC Roots”
- 重点看路径中是否出现
Thread → target → YourRunnable → this$0 → OuterClass
Android 场景下额外注意 Handler 和 Callback
Handler 默认绑定当前线程 Looper,其持有的 Runnable 若是非静态内部类,也会导致 Activity 泄漏。
- 不要在 Activity 里写
new Handler(),改用new Handler(Looper.getMainLooper()) - Handler.post() 的 Runnable 必须是静态的,或用 WeakReference 获取 Activity 实例
- 在 onDestroy() 中调用
handler.removeCallbacksAndMessages(null)清空待执行任务


















