静态变量本身不占堆内存但其引用对象在堆中,若引用不置空则GC无法回收,易致OOM;预防关键在于管控静态变量对对象的持有,如限制静态集合容量、使用WeakReference、单例避免强引Activity、工具扫描与显式清理结合。

静态变量本身不占堆内存,但它持有的对象在堆里;只要引用不置空,GC就无法回收——这才是OOM的真正起点。预防的关键不是禁用static,而是管住它的“手”,让它不乱抓、不长期攥着。
静态集合类必须设限或自动淘汰
ArrayList、HashMap 这类静态容器是泄漏高发区,它们像永不关门的仓库,只进不出。
- 加数据前判断容量或时间戳,超限时调用 clear() 或移除旧项
- 优先用 LinkedHashMap 并重写 removeEldestEntry() 实现 LRU 缓存逻辑
- 避免写 public static List<String> logs = new ArrayList<>(); 这类无清理机制的结构
- 大缓存场景改用 WeakReference<T> 包装值,让 GC 在内存紧张时可主动回收
单例与 Context 引用要彻底“去 Activity 化”
Android 中最典型的 OOM 场景:静态单例持有了 Activity 的强引用,导致整个界面树锁死在内存里。
- 单例内部只使用 getApplicationContext(),绝不保存 Activity、Fragment 或 View 的 this
- 如需注册回调或监听器,一律用 WeakReference 包一层,断开强引用链
- 初始化单例不要放在 Activity 的 onCreate 里传参,避免隐式绑定生命周期
- 配置变更(如横竖屏)后,检查是否残留旧 Activity 的引用
工具扫描 + 显式清理双保险
靠人工记忆 static 字段位置和清理时机不可靠,必须建立工程化约束。
立即学习“Java免费学习笔记(深入)”;
- 上线前用 VisualVM 或 MAT 扫描堆转储,重点过滤 java.util.* 和 android.* 下的静态引用链
- 每个 public static 字段都配套提供 reset() 或 clearCache() 方法,并在 Application#onTerminate 或进程退出前调用
- CI 流程中加入静态分析插件(如 FindBugs / SpotBugs),对 static + Collection / Context / Bitmap 组合发出告警
- 非必要不写静态工具类缓存,改用 ThreadLocal 隔离线程级实例更安全
大对象与硬编码缓存坚决禁止
10MB 的 byte[]、未压缩的 Bitmap、全量 JSON 数据塞进 static 字段,等于在堆里埋雷。
- 禁用类似 private static byte[] buffer = new byte[1024 * 1024 * 100]; 的硬编码大数组
- 图片/文件缓存走专业方案(如 Glide 内置内存策略),不手写 static Map<String, Bitmap>
- JSON 解析器等轻量单例可 static,但解析结果缓存必须带 TTL 或 LRU 控制
- 流式处理大数据时,用分页+局部变量替代全局 static 集合暂存


















