当JVM在垃圾回收期间崩溃(segfaults)时,我该如何找出正在被收集的内容?

12

我在JVM中总是在应用程序的大致相同阶段收到段错误,但在崩溃报告中堆栈跟踪不同。然而,它似乎总是发生在GC期间。

由于崩溃发生在我尝试过的三个JVM(OpenJDK 6、Oracle 1.6.0_25和1.7.0)以及每个JVM使用的两个GC(Parallel Collector和CMS)中,并且它发生在应用程序的大致相同区域,我想,如果我能找到GC正在尝试收集的内容,我可能会发现我的代码中存在某些异常情况导致崩溃。

  • 有哪些编码实践被广泛认为对GC有问题?
  • 有哪些方法可用于诊断此问题?
  • 我能否就触发此问题的应用程序位置进行任何猜测?
  • 可以尝试调整哪些(GC调整)参数以缩小问题范围?
  • 是否有一种方法可以在堆转储中找到(可能)存在问题的数据?

添加了JNI标签,因为正如Peter Lawrey已经指出的那样,这很明显是一些JNI库中的错误。 - Voo
我非常有兴趣看到是什么导致了崩溃。 - Casey
我成功地在没有 JNI 的情况下崩溃了 Sun JVM。 - Casey
无论如何,这是Eclipselink。我知道。它必须离开。它早就应该被淘汰了。我会自己处理它。 - Hanno Fietz
1
@Casey 当然可以,但是相比于某些损坏JNI函数的可能性,JVM实现中出现错误的可能性有多大呢? - Voo
这可能会有所帮助:http://stackoverflow.com/questions/5395337/throw-exception-when-java-jni-experiences-segmentation-fault - Prasanna Talakanti
4个回答

8

如果您有处理内存不正确的JNI库,则会发生这种情况。问题不会立即显示。但是当执行GC时,它会扫描所有内存,遇到损坏的引用并终止JVM。也就是说,自上次完整GC以来,可能随时发生损坏。


听起来很难调试。我有什么办法吗? - Hanno Fietz
1
@RaedWald,如果没有底层JVM中的错误(这是可能的,但不太可能),你无法在纯Java代码中产生段错误。GC必须查看(并遍历)所有指针,因此,如果您将垃圾写入其中之一,它就会被绊倒,这就是全部。 - Voo
有没有办法我可以在堆转储中识别出有问题的数据?我可能能够创建一个可能包含它的堆转储。 - Hanno Fietz
你无法在纯Java代码中产生段错误。我知道。我应该说“在调用JNI代码的finalizer中出现了一个bug”。 - Raedwald
@Readwald 嗯好的,是的我们无法缩小范围。我们所知道的是:某些调用 JNI 代码导致了堆栈损坏,出现问题的位置并不重要(而且不能保证 - 可能是终结器,也可能是其他任何东西)。实际上,在 GC 的同时,终结器甚至不会被执行:它们在独立的线程中运行,同时与程序的其余部分一起执行。 - Voo
显示剩余3条评论

1
  • 段错误在转储的开头有特定的错误代码http://en.wikipedia.org/wiki/Segmentation_fault

  • 您可以使用Thread.dumpStackTrace来查看应用程序中发生了什么。如果您确切地知道应用程序在某个操作或事件后会冻结或即将冻结,您可以使用CTRL + break windows或CTRL + \来获取线程转储并查看正在发生的情况。

  • 与其模糊地猜测,不如注释掉代码的某些部分,以找出哪个循环、对象、缓冲区或字符串需要太长时间。

  • 根据您的情况,您可以考虑一些特定的工具。


1
我们也遇到了类似的问题。我们没有发现任何模式,它是相当随机的,但会出现在GC或Full GC上。对我们来说,问题是与RAM模块有关。我们使用Ubuntu服务器上的MemTest86+进行了识别。

0
  • 我建议你获取线程转储和堆转储,可以通过命令行或使用工具如Visual VM来完成
  • 我认为堆转储作为JVM内存的快照将提供有关活动对象及其分配的信息。如果使用Visual VM分析堆,则会提供有关堆上所有对象的详细报告
  • 我建议您将应用程序的GC收集增加到冗长模式,并使用类似tagtraum的工具进行分析。
  • 如果您可以附加一个JVM profiler,那么可以提供大量信息;如果您对导致问题的工作流程有一般的想法,那么只需在隔离中进行分析

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接