静态集合类是内存泄漏高频场景,因其生命周期与jvm一致,若未主动清理,所持对象无法被gc回收;应避免滥用static map/list,改用带过期机制的concurrenthashmap或caffeine缓存,并确保有淘汰策略与清理入口。

预防内存溢出,关键在于识别并规避那些看似无害、实则容易累积内存压力的代码写法。很多问题不是单次操作导致的,而是长期运行中逐步堆积的结果。
静态集合类长期持有对象引用
静态 Map、List、Set 等容器一旦声明为 static,其生命周期与类加载器一致,除非显式清空或应用重启,否则其中的对象无法被回收。尤其当 key 或 value 是业务对象时,极易形成隐性内存泄漏。
- 避免直接用
static Map<string object></string>做缓存,改用带过期机制的ConcurrentHashMap+ 定时清理,或选用Caffeine等成熟缓存库 - 若必须使用静态集合,确保有明确的淘汰策略(如 LRU)、容量上限和主动清理入口
- 特别注意 Spring 中的
@Component单例 Bean 内部维护的静态或成员集合,它们同样具备长生命周期
字符串拼接与大对象创建不当
频繁使用 + 拼接字符串,在循环中反复创建 String 对象,会触发大量临时对象分配;而一次性加载超大文件、JSON 或图片到内存,也容易突破堆限制。
- 循环内拼接字符串统一用
StringBuilder(非线程安全场景)或StringBuffer(需同步时) - 避免在方法内直接
new byte[1024 * 1024 * 100](100MB),改用流式处理或分块读取 - 解析大型 JSON 时优先选用
JsonParser流式 API,而非一次性ObjectMapper.readValue(json, TypeReference)
资源未释放与监听器未注销
未关闭的 IO 流、数据库连接、网络 Socket,以及注册后未移除的事件监听器,不仅占用堆外内存,还可能间接持有着堆内对象引用,阻碍 GC。
- 所有实现
AutoCloseable的资源,必须用try-with-resources语法,杜绝finally中遗漏close() - GUI 或事件驱动框架中,动态添加的监听器(如 Swing 的
addMouseListener、Android 的registerReceiver)务必配套注销逻辑 - 使用线程池时,避免在线程内长期持有外部对象引用;任务执行完及时置空上下文变量
递归调用与线程栈配置失衡
深度递归会快速耗尽单个线程的栈空间,抛出 StackOverflowError;而盲目增大 -Xss 又会导致可创建线程数锐减,在高并发下引发 OutOfMemoryError: unable to create new native thread。
- 递归逻辑必须有明确、可靠的终止条件;深度超过 50 层时建议转为迭代实现
- 避免在递归中创建大对象或进行 I/O;必要时通过尾递归优化(Java 不原生支持,可用循环模拟)
- 线程池应复用线程,而非每次新建;
-Xss建议保持默认(1MB)或设为 256k–512k,再配合合理的核心/最大线程数控制
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











