关键是要避免隐式访问导致内存泄漏:优先用静态内部类+显式传参;必须访问实例时用WeakReference并每次判空;避免局部变量无意捕获;长生命周期容器需手动清理。

关键不是“怎么访问”,而是“要不要隐式访问”。非静态内部类能直接读外部类字段,靠的是编译器悄悄加的 this$0 强引用——这正是内存泄漏的起点。要安全访问,就得主动切断这条隐式链。
优先改用静态内部类 + 显式传参
只要内部逻辑不依赖外部类的实例状态(比如不需要调 this.finish() 或读 user.name),就该声明为 static。它天然没有 this$0 字段,生命周期与外部类彻底解耦。
- 把
new Runnable() { ... }换成static class BackgroundTask implements Runnable - 需要数据时,通过构造方法传入具体值:比如
new BackgroundTask(userId, timeoutMs),而不是new BackgroundTask(Outer.this) - 静态内部类仍可自由访问外部类的
static成员,无需额外处理
必须访问实例时,用 WeakReference 包装并判空
如果真要触发外部类的实例行为(如更新 UI、关闭资源),又无法保证调用时机在外部类存活期内,WeakReference 是安全兜底手段。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 在静态内部类中声明:
private final WeakReference<outer> outerRef;</outer> - 构造时传入:
outerRef = new WeakReference(outerInstance); - 每次使用前必须判空:
Outer outer = outerRef.get(); if (outer != null) { outer.updateUI(); } - 切忌在判空后缓存
outer的强引用,否则等于白做
避免局部变量“无意捕获”导致的隐式引用
即使写了匿名类或 Lambda,只要里面用了外部类的实例字段或方法,编译器就会生成 this$0。可以用 final 局部变量截断。
立即学习“Java免费学习笔记(深入)”;
- 把
handler.post(() -> doSomething(data, flag));改成: final String snapData = this.data;final boolean snapFlag = this.flag;handler.post(() -> doSomething(snapData, snapFlag));
长生命周期容器里必须主动清理
静态 Handler、全局线程池、EventBus 订阅、广播接收器……这些地方哪怕用了静态内部类+WeakReference,也得手动解绑。
- 在 Activity.onDestroy() 或 Fragment.onDetach() 中,清空 Handler 消息:
handler.removeCallbacksAndMessages(null) - 取消已提交的线程任务:
future.cancel(true) - 注销监听器:
eventBus.unregister(this)或view.setOnClickListener(null)

















