如何在运行我的代码的JVM中调试发生的Segfault?


问题内容

我的Java应用程序开始定期崩溃,原因是SIGSEGV和堆栈数据转储以及文本文件中的信息负载。

我已经调试了gdb中的C程序,并且已经从我的IDE中调试了Java代码。我不确定如何在正在运行的Java程序中处理类似C的崩溃。

我假设我不在这里查看JVM错误。其他Java程序运行良好,Sun的JVM可能比我的代码更稳定。但是,我不知道如何用Java代码引起段错误。肯定有足够的可用内存,当我上次检入探查器时,堆使用率约为50%,偶尔出现峰值约80%。我可以调查任何启动参数吗?解决此类错误时,什么是好的清单?

尽管到目前为止我还不能可靠地重现该事件,但它似乎也不是完全随机发生的,因此测试并不是完全不可能的。

预计到达时间:一些细节

(我正在寻找一种通用的方法,因为实际的问题可能非常具体。不过,我已经收集了一些信息,可能有价值。)

不久前,在升级CI服务器之后,我遇到了类似的麻烦(有关更多详细信息,请参见此处),但是这次修复(设置-XX:MaxPermSize)没有帮助。

进一步的调查显示,在崩溃日志文件中,标记为“当前线程”的线程绝不是我的线程,而是称为“ VMThread”的线程或称为“ GCTaskThread”的线程-
如果是后者,则还附加注释“(已退出)”,如果是前者,则GCTaskThread不在列表中。这使我认为问题可能出在GC操作即将结束时。


问题答案:

我假设我不在这里查看JVM错误。其他Java程序运行良好,Sun的JVM可能比我的代码更稳定。

我认为您不应该做这个假设。如果不使用JNI,则您将无法编写导致SIGSEGV的Java代码(尽管我们知道它会发生)。我的意思是,发生这种情况时,它要么是JVM中的错误(并非闻所未闻),要么是某些JNI代码中的错误。如果您自己的代码中没有任何JNI,这并不意味着您没有使用某些库,因此请查找该库。当我以前看到这种问题时,它在图像处理库中。如果罪魁祸首不在您自己的JNI代码中,则可能无法“修复”该错误,但是您仍然可以解决该错误。

首先,您应该在同一平台上获得备用JVM,然后尝试重现它。您可以尝试以下替代方法之一

如果无法重现,则可能是JVM错误。由此,您可以使用特定的知识来授权特定的JVM或搜索错误数据库,并获得建议的解决方法。(即使可以重现它,许多JVM实现也只是对Oracle
Hotspot实现的调整,因此它可能仍然是JVM错误。)

如果可以使用替代的JVM重现它,则 可能
是您有一些JNI错误。查看您正在使用的库以及它们可能在进行的本机调用。有时,对于同一库或执行几乎相同功能的替代库,存在替代的“纯Java”配置或jar文件。

祝好运!