Java GC 在低内存停止和崩溃程序上



我在java程序中使用并行GC。但是当 jvm 的可用内存少于 ~400mb 时,GC 开始消耗所有 CPU。一段时间后,jvm 崩溃与java.lang.OutOfMemoryError: GC overhead limit exceeded.但是我正在用Runtime.getRuntime().freeMemory()打印可用内存量,并且我确定jvm具有~400mb的可用空间。我试图将-XX:MinHeapFreeRatio设置为 1 或 5,但它使一切都变得最糟糕。

如何配置 GC 或我应该选择哪一个来防止它消耗所有 CPU 并崩溃 jvm? 我的 jvm 标志-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Xmx3800m -server -Djava.library.path="native_libs"

错误

当 JVM 花费大部分时间进行垃圾回收而无法在垃圾回收周期结束时释放大量内存时,java.lang.OutOfMemoryError: GC overhead limit exceeded会发生此错误。可以在此处找到很好的详细说明。请注意,这并不一定意味着您的内存不足!您可能还剩下很多内存,但垃圾回收器可能无法释放任何内容,并且提前放弃。

原因

由于您说在此异常发生时您只需要 50 MB 内存,因此您可能会泄漏内存。仅使用 50 MB 内存不会导致垃圾回收器像这样失败。当您仍有对不再需要的对象的引用时,会发生内存泄漏。当太多对象仍可访问时,垃圾需要很长时间,并且垃圾回收器无法释放任何对象,因为它们仍可供程序访问。

解决方案

您需要找到内存泄漏的来源。常见原因是将对象保留在列表、映射和集等数据结构中而不删除它们。您可以进行堆转储,这实质上是将 java 程序内存中的所有对象保存到一个文件中,然后您可以检查该文件。您可以通过将-XX:+HeapDumpOnOutOfMemoryError标志添加到java命令,将 Java 配置为在发生内存不足异常时执行堆转储。有关堆转储存储位置的更多详细信息,请参阅此问题 对 JBoss 的堆转储使用 HeapDumpOnOutOfMemoryError 参数。然后,下次崩溃时,您可以使用像 Eclipse MAT 这样的工具来检查堆转储并查看哪些对象正在消耗内存。这将为您指出内存泄漏的方向,以便您可以修复它。

我的应用程序在旧世代中有很多东西,所以我如何理解 GC 试图为年轻一代释放足够的内存,并且经常制作完整的 gc。因此,通过减少年轻一代的大小,我扩展了我大量使用的旧一代的大小。

要减少年轻一代的大小,您可以使用-XX:MaxNewSize-XX:NewRatio-XX:NewSize。我用了-XX:MaxNewSize.您可以在此处阅读有关它的信息 https://docs.oracle.com/cd/E19900-01/819-4742/abeik/index.html

java.lang.OutOfMemoryError异常是内存泄漏的一个常见迹象。

通常,当没有足够的空间来分配 Java 堆中的对象时,会引发此错误。在这种情况下,垃圾回收器无法腾出空间来容纳新对象,并且堆无法进一步扩展。

此外,当没有足够的本机内存来支持 Java 类的加载时,可能会引发此错误。

在极少数情况下,当花费过多时间进行垃圾回收并且释放的内存很少时,可能会引发java.lang.OutOfMemoryError

详情请见此处

相关内容

最新更新