使用WeakReference验证GC回收时出现java.lang.OutOfMemoryError的原因咨询
为啥用WeakReference还会OutOfMemoryError?
嘿,这个坑我之前踩过!明明加了-Xmx50m内存限制,理论上弱引用该被GC回收,但还是OOM,大概率是这几个原因:
1. 你的弱引用对象被强引用偷偷持有了
这是最常见的问题!WeakReference本身不会阻止GC回收,但如果你的代码里还有其他地方用强引用(比如普通变量、集合)拿着这个对象,那GC绝对不会碰它。举个反面例子:
List<Object> strongHolders = new ArrayList<>(); while (true) { Object obj = new Object(); WeakReference<Object> weakRef = new WeakReference<>(obj); strongHolders.add(obj); // 这里的强引用直接把对象锁死了! // 后续即使weakRef.get()可能返回null,但strongHolders里的强引用还在,对象永远不会被回收 }
赶紧检查你的代码,有没有类似的“隐藏强引用”——比如对象被存到了静态集合、ThreadLocal,或者某个长期存活的类的实例变量里。
2. GC触发不及时,对象创建速度跑赢了GC
JVM的GC触发是有条件的,比如年轻代的Eden区满了才会触发Minor GC,老年代满了才会触发Full GC。如果你的代码疯狂创建对象,速度快到GC还没来得及启动、完成回收,内存就被彻底占满了,那OOM就会发生。
比如你在一个无限循环里每秒创建上万个对象,即使都是弱引用包装的,但在GC启动前,这些对象都还在内存里,直接把50M堆内存撑爆。
3. Finalizer线程拖后腿了
如果你的弱引用对象重写了finalize()方法,那GC回收它之前,需要交给Finalizer线程去执行这个方法。如果Finalizer线程被阻塞(比如finalize()里有耗时操作、死锁,或者线程本身挂了),这些对象就会堆积在Finalizer队列里,没法被彻底回收,慢慢把内存耗光。
排查建议
- 用
jmap -dump:format=b,file=heap.hprof <pid>导出堆快照,然后用VisualVM或者MAT分析,看看哪些对象占了内存,找它们的引用链,确认是不是有强引用没释放。 - 加上GC日志参数:
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps,看看GC是不是真的在触发,以及每次回收了多少内存——如果GC根本没怎么回收,那肯定是有强引用;如果回收了但对象创建更快,那就要调整GC策略或者控制对象创建速度。 - 检查代码里有没有重写
finalize()的地方,尽量避免用这个方法,它不仅会拖慢GC,还容易导致内存泄漏。
内容的提问来源于stack exchange,提问作者vermaji
相关产品推荐
相关产品推荐

