使用Java JNI时是否可以调试核心转储?

我的应用程序主要是Java,但对于某些计算,它使用C ++库。 我们的环境是在RedHat 3上运行的Java 1.6(很快就是RedHat 5)。

我的问题是C ++库不是线程安全的。 为了解决这个问题,我们运行多个单线程“工作”流程,并让他们从中央工作管理器开始工作,也是用C ++编写的。 我们的Java应用程序通过第三方产品调用C ++ Work Manager。

出于各种原因,我们希望重新编写C ++ Work Manager和worker。 我赞成用Java编写它们,在每个worker中使用JNI来调用C ++库。

主要问题是如果C ++库核心转储会发生什么。 不幸的是,这很常见,我们需要能够看到C ++库中的哪一行导致了这个问题,例如通过检查GDB之类的回溯。

我的同事认为,分析核心转储是不可能的,因为像GDB这样的工具不了解Java生成的核心文件。

我希望他们错了,但在进一步推动我的想法之前我需要确定。

分析Java / JNI生成的核心转储的最佳方法是什么?

就在这里。 每次JVM因JNI部分中的SIGSEGV而崩溃,您将在$ JAVA_HOME / bin目录中获得带有核心转储的文件。 它通常命名为hs_err_PID.log。

您可以在此处获取更多信息。 这是一个有点相关的stackoverflow问题。

要将核心文件读入gdb,您必须将java虚拟机添加到其中。 那是

gdb /usr/local/jdk1.8.0_66/bin/java core 

它很可能会告诉你没有找到大量的符号(这是正常的,这些是JVM符号)。 但是,如果键入“bt”,则崩溃的JNI调用可能会出现在堆栈跟踪中。 在我的情况下,我在我写的本机库中崩溃的一个例子是:

 (gdb) bt #0 0x00007fd61dfcd107 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 #1 0x00007fd61dfce4e8 in __GI_abort () at abort.c:89 #2 0x00007fd61d8d3795 in os::abort(bool) () from /usr/local/jdk1.8.0_66/jre/lib/amd64/server/libjvm.so #3 0x00007fd61da71e23 in VMError::report_and_die() () from /usr/local/jdk1.8.0_66/jre/lib/amd64/server/libjvm.so #4 0x00007fd61d8d8fbf in JVM_handle_linux_signal () from /usr/local/jdk1.8.0_66/jre/lib/amd64/server/libjvm.so #5 0x00007fd61d8cf753 in signalHandler(int, siginfo*, void*) () from /usr/local/jdk1.8.0_66/jre/lib/amd64/server/libjvm.so #6  

前6帧都与崩溃过程本身有关。 捕获并发送了一个信号。 虽然我们不知道确切的function,但无所谓。 从第7帧开始,我们在我们编写的JNI库中。 如果它还附有符号,你会看到它们。

 #7 0x00007fd5ff43bf7e in FftResampler::resample(Complex const*, int) () from /I/home/werner/BpmDj/NextGen/Beta/Desktop/test/libzathras-46703-64.so #8 0x00007fd5ff43ddcf in TimeStretcher::rescaleEnvelopeSlow(PeakMap const*, Peak*) () from /I/home/werner/BpmDj/NextGen/Beta/Desktop/test/libzathras-46703-64.so #9 0x00007fd5ff43e4a5 in TimeStretcher::transferPeak(Frame*, Frame*) () from /I/home/werner/BpmDj/NextGen/Beta/Desktop/test/libzathras-46703-64.so #10 0x00007fd5ff43e679 in TimeStretcher::transferPeaks(Channel*) () from /I/home/werner/BpmDj/NextGen/Beta/Desktop/test/libzathras-46703-64.so #11 0x00007fd5ff43eb3a in TimeStretcher::putStereo(float const*, int) () from /I/home/werner/BpmDj/NextGen/Beta/Desktop/test/libzathras-46703-64.so #12 0x00007fd5ff43edbf in TimeStretcher::processStereo(float const*, int, float*) () from /I/home/werner/BpmDj/NextGen/Beta/Desktop/test/libzathras-46703-64.so #13 0x00007fd5ff43b45d in Java_org_yellowcouch_bpmdj_mixedit_audio_JavaTimeStretcher_processStereo () from /I/home/werner/BpmDj/NextGen/Beta/Desktop/test/libzathras-46703-64.so 

从第14帧开始,我们又回到了java的土地上。

 #14 0x00007fd6097a29e1 in ?? () #15 0x00007fd5d6ee6580 in ?? () #16 0x00000000853f53e8 in ?? () #17 0x00000000d803c340 in ?? () #18 0x00000000d80564e8 in ?? () #19 0x00007fd61e773609 in _L_unlock_554 () from /lib/x86_64-linux-gnu/libpthread.so.0 

所以你看到通过gdb从核心文件中获取一些信息并非完全不可能。 只是不要忘记将jvm添加为第一个参数。

gdb可能无法找到本机库本身。 在这种情况下,您可能希望手动加载符号,如下所示:

gdb>符号文件libzathras-46703-64.so

如果您想了解更多信息,可能需要在启用调试信息的情况下编译c / c ++代码。 通常使用mingw和gcc编译器,您可以在命令行选项中添加-g。 这将为您提供以下信息,其中包括行号等。

 #7 FftResampler::resample (this=this@entry=0x7f4bf8f36100, cpx=cpx@entry=0x7f4bf8ed1ea0, n=) at timestretcher.cpp:347 #8 0x00007f4c51605dcf in TimeStretcher::rescaleEnvelopeSlow ( this=0x7f4bf8ec1e10, table=0x7f4bf90f4c20, borders=0x7f4bf8fd27a0) at timestretcher.cpp:878 #9 0x00007f4c516064a5 in TimeStretcher::transferPeak ( this=this@entry=0x7f4bf8ec1e10, prevFrame=prevFrame@entry=0x7f4bf8fde6f0, frame=frame@entry=0x7f4bf8fb2650) at timestretcher.cpp:718 #10 0x00007f4c51606679 in TimeStretcher::transferPeaks ( this=this@entry=0x7f4bf8ec1e10, channel=channel@entry=0x7f4bf8ec9e90) at timestretcher.cpp:687 #11 0x00007f4c51606b3a in TimeStretcher::putStereo ( this=this@entry=0x7f4bf8ec1e10, in=in@entry=0x7f4bf8eb9e00, time=time@entry=-1395) at timestretcher.cpp:1483 #12 0x00007f4c51606dbf in TimeStretcher::processStereo ( this=this@entry=0x7f4bf8ec1e10, in=in@entry=0x7f4bf8eb9e00, time=time@entry=-1395, out=0x7f4bf90f4c60) at timestretcher.cpp:1567 #13 0x00007f4c5160345d in Java_org_yellowcouch_bpmdj_mixedit_audio_JavaTimeStretcher_processStereo (env=0x7f4bf90f71f8, obj=, handle=139964275465728, in=0x7f4bed136468, inIdx=, time=-1395, out=0x7f4bed136480) at timestretcher-jni.cpp:69