我们有一个应用程序可以生成新的JVM并代表我们的用户执行代码。有时那些内存耗尽,在这种情况下表现得非常不同。有时它们抛出OutOfMemoryError,有时会冻结。我可以通过一个非常轻量级的后台线程来检测后者,该线程在内存不足时停止发送心跳信号。在那种情况下,我们杀死了JVM,但我们永远无法确定未能获得心跳的真正原因是什么。 (它也可能是网络问题或分段错误。)
可靠地检测JVM中内存不足情况的最佳方法是什么?
有没有其他选择或解决方法?垃圾收集设置使JVM自行终止而不是冻结?
编辑:我完全控制了分叉和分叉的JVM以及在这些内部执行的代码,两者都在Linux上运行,如果有帮助,可以使用特定于操作系统的实用程序。
唯一真正的选择是(不幸的是)尽快终止JVM。
因为您可能无法更改所有代码以捕获错误并做出响应。如果你不信任OnOutOfMemoryError
(我想知道为什么它不应该使用Java 8使用的vfork,并且它适用于Windows),你至少可以触发一个堆转储并在外部监视这些文件:
java .... -XX:+HeapDumpOnOutOfMemoryError "-XX:OnOutOfMemoryError=kill %p"
经过一段时间的实验,这是对我们有用的解决方案:
OutOfMemoryError
并立即退出,通过退出代码向控制器JVM发出内存不足信号。Runtime
的消耗内存量。当使用的内存量接近于临界值时,创建一个标志文件,向控制器JVM发出内存不足情况的信号。如果我们从此条件恢复并正常退出,请在退出之前删除该文件。hs_err_pidXXX.log
是否存在并包含“Out of Memory Error”行。 (此文件由java生成,以防它崩溃。)只有在实现所有这些检查之后,我们才能处理分叉JVM内存不足的所有情况。我们相信,从那以后,我们没有错过这种情况发生的情况。
因为fork问题而未使用java标志-XX:OnOutOfMemoryError
,并且未使用-XX:+HeapDumpOnOutOfMemoryError
,因为堆转储超出了我们的需要。
解决方案肯定不是有史以来最优雅的代码,但是为我们完成了这项工作。
如果您对应用程序和配置都有控制权,那么最好的解决方案是查找抛出OutOfMemoryError的根本原因并修复此问题,而不是通过捕获错误或仅重新启动JVM来尝试隐藏症状。
根据您的描述,它肯定看起来JVM上运行的应用程序正在泄漏内存,只是使用配置不足的资源(在您的情况下为内存)运行,或偶尔处理需要异常大块堆的事务。这些案件的解决方案会有所不同: