内存泄漏的真正起点是静态变量持有的对象未及时释放;关键在于管控其引用对象及持有时间,需通过容量限制、弱引用、去Activity化、初始化容错和配套清理机制来防范。

静态变量本身不占堆内存,但它持有的对象在堆里;只要引用不置空,GC 就无法回收——这才是内存泄漏的真正起点。防止的关键不是不用 static,而是管住它“抓什么”和“攥多久”。
静态集合类必须设容量或淘汰机制
ArrayList、HashMap 这类静态容器是泄漏高发区,它们像永不关门的仓库,只进不出。
- 加数据前判断 size 或时间戳,超限时主动 clear() 或 removeEldestEntry()
- 优先用 LinkedHashMap 实现 LRU 缓存,重写 removeEldestEntry() 控制最大条目数
- 避免 public static List<String> logs = new ArrayList<>(); 这类无清理逻辑的写法
- 大缓存场景改用 WeakReference 包装值,让 GC 在内存紧张时可回收
单例与 Context 引用要彻底“去 Activity 化”
Android 中最典型的泄漏:静态单例持有了 Activity 的强引用,导致整个界面树锁死在内存里。
- 单例内部只使用 getApplicationContext(),绝不保存 Activity、Fragment 或 View 的 this
- 如需注册监听器,一律用 WeakReference 包一层,断开强引用链
- 初始化不要放在 Activity 的 onCreate 里传参,避免隐式绑定生命周期
- 配置变更(如横竖屏)后检查是否残留旧 Activity 引用
初始化要可控,失败不阻塞类加载
静态变量在类加载时初始化,若抛异常会导致 NoClassDefFoundError,后续所有调用都失败。
立即学习“Java免费学习笔记(深入)”;
- 复杂初始化放进 static 代码块,并包裹 try-catch,至少记录错误、提供默认值
- 需要延迟加载(如读取配置失败后重试),可用静态内部类单例或双重检查锁
- 多个 static 变量有依赖时,按源码顺序声明,确保基础项先初始化
每个 public static 字段都要配套清理能力
靠人工记忆 static 字段位置和清理时机不可靠,必须工程化约束。
- 每个 public static 字段都配套提供 reset() 或 clearCache() 方法
- 在 Application#onTerminate 或进程退出前统一调用清理方法
- 上线前用 VisualVM 或 MAT 扫描堆转储,重点过滤 java.util.* 和 android.* 下的静态引用链
- CI 流程中加入 SpotBugs 插件,对 static + Collection / Context / Bitmap 组合发出告警


















