了解GC:分配失败并使用临时String对象填充OldGen

时间:2018-04-12 11:14:59

标签: java garbage-collection jvm heap-memory heap-dump

我已经跟进了几个好问题和他们的答案,但我仍有疑问。

这是我理解的,并且希望看到理解是否正确。

只要在YoungGen上分配新内存,

GC(分配失败)就会启动。

此外,根据对象的大小,可能必须将某些对象推送到OldGen,并且可以将更大的对象直接移动到OldGen。

应用程序行为:“分配失败”的原因是创建了大量字符串。在使用JFR和HeapDump进一步调试时,所有内容都指向很多char []和String对象,这些对象是在我们的系统中临时创建的(即YoungGen候选者)。其中一些字符串确实很大(每个约25KB)。虽然,根据错误消息,YoungGen中有足够的可用空间,而Heap甚至可能无法接近最大内存。

在同一时间,OldGen正在增加,即使在完整的GC之后也没有得到清理。可能会有另一个内存泄漏,但没有任何指向这一点。所以,我不明白为什么即使在完整的GC之后OldGen仍保持在同一水平。

除了验证我的理解之外,问题是可以创建大量临时String / char []对象(通过strA + strB,new String()/ StringBuilder()。toString(),String.split(),String.substring(),Stream->缓冲区转换等)导致GC非常频繁地运行,即使应用程序在YoungGen和堆中有大量可用内存一般来说?如果是,何时以及有哪些替代方案?

谢谢!

1 个答案:

答案 0 :(得分:0)

我会说答案是有条件的。

请记住,年轻人分为3个部分,即伊甸园,S0和S1,这意味着你没有像你想象的那样拥有年轻人的记忆。如果你溢出其中一个幸存者空间,其余的将被推到旧的(过早的促销),填补旧的gen。另请注意,从年轻人到老年人的晋升是基于gc周期的数量。如果你有频繁的年轻gen gc,那些应该是短命的对象被移动到旧的gen(因为你还没有完成temp对象),那么你将填补旧的gen。另请注意,仅仅因为您执行完整的gc,无法保证您实际上会获得任何内存。 因此,使用像censum这样的工具来分析您的gc日志,特别是过早推广。 可能你必须调整年轻的gen / old比率。