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

我的Java应用程序已经开始定期崩溃,使用SIGSEGV和堆栈数据转储以及文本文件中的大量信息。

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

我假设我不是在看这里的JVM错误。 其他Java程序运行得很好,Sun的JVM可能比我的代码更稳定。 但是,我不知道如何使用Java代码导致段错误。 肯定有足够的可用内存,当我上次检查分析器时,堆使用率约为50%,偶尔会出现80%左右的峰值。 我可以调查任何启动参数吗? 在接近像这样的bug时,什么是好的清单?

虽然我不能够可靠地再现事件,但它似乎也不是完全随机发生的,所以测试并非完全不可能。

ETA:一些血腥的细节

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

不久之前,升级我的CI服务器之后遇到了类似的问题(详情请见这里 ),但是这次修复(设置-XX:MaxPermSize )没有帮助。

进一步的调查显示,在崩溃日志文件中,标记为“当前线程”的线程永远不是我的,但是一个名为“VMThread”或一个名为“GCTaskThread” – 我是后者,它还标有注释“(已退出)”,如果是前者,则GCTaskThread不在列表中。 这让我想到问题可能是在GC操作结束时。

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

我认为你不应该做出这样的假设。 在不使用JNI的情况下 ,您不应该编写导致SIGSEGV的Java代码(尽管我们知道它发生了)。 我的观点是,当它发生时,它或者是JVM中的错误(不是闻所未闻)或者是某些JNI代码中的错误。 如果你自己的代码中没有任何JNI,那并不意味着你没有使用某个库,所以寻找它。 当我之前看到这种问题时,它出现在图像处理库中。 如果罪魁祸首不在您自己的JNI代码中,您可能无法“修复”该错误,但您仍然可以解决它。

首先,您应该在同一平台上获得备用JVM并尝试重现它。 您可以尝试其中一种替代方案 。

如果你无法重现它,它可能是一个JVM错误。 从那里,你可以命令一个特定的JVM或搜索bug数据库 ,使用你知道的如何重现它,并可能得到建议的解决方法。 (即使你可以重现它,许多JVM实现只是对Oracle的Hotspot实现的调整,所以它可能仍然是一个JVM错误。)

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

祝你好运!

除非您有本机代码,否则以下内容几乎肯定无用。 但是,这里有。

  1. 在java调试器中启动java程序,在可能的sigsegv之前使用断点。
  2. 使用ps命令获取java的processid。
  3. gdb / usr / lib / jvm / sun-java6 / bin / java processid
  4. 确保将gdb’handr’命令设置为在SIGSEGV上停止
  5. 从断点继续java调试器。
  6. 等待爆炸。
  7. 使用gdb进行调查

如果您真的设法让JVM在没有您自己的本机代码的情况下使用sigsegv,那么您不太可能对下一步会看到什么有所了解,并且您可以做的最好的事情就是将测试用例推送到bug上报告。

我在http://www.oracle.com/technetwork/java/javase/crashes-137240.html找到了一个很好的列表。 当我在GC期间遇到崩溃时,我会尝试在垃圾收集器之间切换。

我尝试在串行和并行GC之间切换(后者是64位Linux服务器上的默认值),这只是相应地更改了错误消息。

在分析器中进行全新分析后,将最大堆大小从16G减少到10G(这使我的堆使用率在8G时变平)确实导致“虚拟内存”占用空间明显减少(16G而不是60),但我不知道甚至不知道这意味着什么,互联网说,这没关系。

目前,JVM以客户端模式运行(使用-client启动选项,从而覆盖-server的默认值)。 到目前为止,没有崩溃,但性能影响似乎相当大。

如果你有一个corefile,你可以尝试在它上面运行jstack,这会给你一些更容易理解的东西 – 参见http://download.oracle.com/javase/6/docs/technotes/tools/share/jstack.html ,虽然如果它是gc线程中的一个错误,它可能不是那么有用。

尝试检查c程序carh是否导致java崩溃。使用valgrind知道无效并且还交叉检查堆栈大小。