谢谢。
有一种情况可能导致OOM,既不与堆相关,也不与地址空间相关:当JVM决定GC运行时间过长时。
请参阅这里。
换句话说,对于您最初的问题,“如果没有足够的内存分配,会在抛出OutOfMemoryError之前强制运行gc”,答案是肯定的。
(从上面的链接可以看出,gc /运行代码的比率为98%/ 2%,已经非常高了)
(注意2:这适用于Sun / Oracle的JVM,其他实现不清楚)
如果GC在释放内存时花费太多时间而不释放大量内存,则可能会出现'java.lang.OutOfMemoryError: GC overhead limit exceeded'错误,详情请参见此问题。
在OutOfMemoryError抛出之前,GC被强制运行。如果JVM实现了几种类型的GC(如“并发”或“部分”),则在JVM放弃之前会运行“停止世界”GC,因此已尽一切可能避免该错误。
被引用的异常是,如果GC重复运行并仅恢复了微不足道的存储空间(并且堆大小不能进一步扩展),则它将放弃而不是继续以“爬行”模式运行。理论上,对于这种情况,略微增加堆大小将允许“良好”的应用程序正常运行,但正在缓慢消耗堆(这并不罕见)的应用程序将无法从轻微的堆增加中受益,并且稍后也会遇到同样的故障。
[需要注意的是,在GC频繁运行的情况下,如果应用程序表现良好并巧合地运行在堆限制附近,则增加堆大小可能会显着减少GC开销。 (当然,将堆大小增加到大于可用RAM的值通常会使应用程序运行更慢。)]
看起来如果你编写的代码适当,就不会遇到OOM。因为JVM会在遇到OOM之前运行垃圾回收。
所以如果你遇到OOM,很可能是你的代码有一些内存泄漏。请检查。
垃圾回收器通常会在抛出OutOfMemoryError
之前尝试找到内存,但是我偶尔看到可以重现的例子,垃圾回收器没有完全跟上进度,调用System.gc()
可以避免异常。
但这很少见,通常不应该自己尝试触发垃圾回收。