非静态内部类隐式持有外部类实例引用,易致内存泄漏;静态内部类无此引用,独立存在,仅可访问外部类静态成员,且可定义静态成员。

关键区别在于:非静态内部类(即普通成员内部类)默认持有外部类实例引用,而静态内部类不持该引用——这是内存泄漏风险差异的根源。
非静态内部类自动持有外部类引用
编译器会在其构造方法中隐式注入 OuterClass.this,使它能直接访问外部类所有成员(包括 private 字段和方法)。这种设计虽方便,但也意味着只要该内部类实例还活着,外部类实例就无法被 GC 回收。
- 典型泄漏场景:在 Activity 中定义非静态 Handler 或 Thread,若任务未完成而 Activity 已 finish,Handler/Thread 持有 Activity 引用 → Activity 内存无法释放
- 即使把外部类对象显式置为 null,只要内部类实例被静态变量、单例、线程池等长生命周期对象持有,泄漏仍会发生
- 不能定义静态字段或静态方法(编译报错),因为它依附于外部类实例存在
静态内部类不持有外部类引用
它本质是一个“独立的顶层类”,只是命名空间嵌套在外部类中。编译后生成 Outer$StaticInner.class,与外部类无隐式关联。
- 无法直接访问外部类的非静态成员;如需使用,必须显式传入(例如通过构造参数),此时可控性更强
- 适合做工具类、配置类、懒汉式线程安全单例(利用类加载机制保证初始化线程安全)
- 本身不会导致外部类泄漏,但若你手动持有外部类强引用(比如保存 Activity 实例),仍可能引发泄漏
如何规避内存泄漏风险
核心原则是:**生命周期长的对象,不要依赖生命周期短的对象**。
- Android 中避免在 Activity/Fragment 内使用非静态 Handler、AsyncTask、Runnable、TimerTask 等
- 改用静态内部类 + WeakReference<Activity> 安全访问上下文
- 使用静态内部类时,若需回调外部类方法,优先通过接口解耦,而非直接持有 Activity/Context 实例
- 局部内部类和匿名内部类也属于非静态类型,同样隐式持外部类引用,需同等警惕

















