2009-11-19 7 views
7

Meine Anwendung ist meist Java, aber für bestimmte Berechnungen verwendet eine C++ - Bibliothek. Unsere Umgebung ist Java 1.6, das auf RedHat 3 (bald RedHat 5) läuft.Ist es möglich, Core Dumps zu debuggen, wenn Java JNI verwendet wird?

Mein Problem ist, dass die C++ - Bibliothek nicht Thread-sicher ist. Um dies zu umgehen, führen wir mehrere, "single-threaded" "Worker" -Prozesse aus und erledigen diese Aufgaben von einem zentralen Work Manager aus, der ebenfalls in C++ geschrieben ist. Unsere Java-Anwendung ruft den C++ Work Manager über ein Drittanbieterprodukt auf.

Aus verschiedenen Gründen möchten wir den C++ Work Manager und Mitarbeiter neu schreiben. Ich bin dafür, sie alle in Java zu schreiben, indem ich in jedem Worker JNI verwende, um die C++ - Bibliothek aufzurufen.

Das Hauptproblem ist, was passiert, wenn der C++ - Bibliothekskern ablegt. Leider ist dies ziemlich üblich, und wir müssen in der Lage sein zu sehen, welche Zeile in unserer C++ - Bibliothek das Problem verursachte, z. indem Sie ein Backtrace in etwas wie GDB untersuchen.

Meine Kollegen glauben, dass es unmöglich sein wird, die Core-Dumps zu analysieren, weil Tools wie GDB Kerndateien von Java nicht verstehen.

Ich hoffe, dass sie falsch sind, aber ich muss sicher sein, bevor ich meine Ideen weiter vorantreiben.

Was ist der beste Weg, um einen Core-Dump aus Java/JNI zu analysieren?

Antwort

7

Ja, gibt es. Jedes Mal, wenn JVM aufgrund eines SIGSEGV im JNI-Teil abstürzt, erhalten Sie eine Datei mit einem Core-Dump im Verzeichnis $ JAVA_HOME/bin. Es wird normalerweise hs_err_PID.log genannt.

Sie können weitere Informationen erhalten here und here. Here ist eine etwas verwandte Stackoverflow-Frage.

+2

Danke Pablo. Kohsukes Artikel ist ausgezeichnet. Wenn ich meinen Kollegen leider sage, dass sie Assembler verstehen müssen, um herauszufinden, welche C++ - Zeile den Seg-Fehler verursacht hat, werden sie eine Meile laufen. Ich bin auf Linux und meine .so-Dateien wurden mit dem Debug-Flag kompiliert. Vielleicht wird dies den Prozess erleichtern. –

+1

Sorry, aber eine 'Log'-Datei hat nichts mit dem Coredump zu tun, nach dem der O.P gefragt hat. –

+0

Ich habe diese hs_err_PID Dateien im Verzeichnis/tmp gefunden. – Aman

2

Um die Core-Datei in gdb lesen zu können, müssen Sie die Java Virtual Machine hinzufügen. Das ist

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

wird es sehr wahrscheinlich, dass Sie sagen, dass eine Tonne Symbole nicht gefunden (das ist normal, das sind die JVM Symbole). Der JNI-Aufruf, der abgestürzt ist, könnte jedoch in Ihrem Stacktrace erscheinen, wenn Sie 'bt' eingeben. Ein Beispiel, in meiner Situation, wo ich einen Absturz in einer nativen Bibliothek habe ich geschrieben habe, ist:

(gdb) bt 
#0 0x00007fd61dfcd107 in __GI_raise ([email protected]=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 <signal handler called> 

Die ersten 6 Bilder sind alle mit dem Crash-Prozess selbst verwendet. Ein Signal wurde aufgefangen und versandt. Und obwohl wir die genauen Funktionen nicht kennen, spielt es keine Rolle. Beginnend mit Frame 7, sind wir in der JNI-Bibliothek, die wir geschrieben haben. Und wenn es noch Symbole hatte, werden Sie sie sehen.

#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 

Und ab Frame 14 sind wir zurück in Java Land.

#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 

Sie sehen also, dass es nicht völlig unmöglich ist, einige Informationen aus den Core-Dateien durch gdb zu erhalten. Vergiss nicht, das jvm als erstes Argument hinzuzufügen.

Es ist möglich, dass gdb die native Bibliothek nicht selbst findet. In diesem Fall sollten Sie die Symbole wie folgt manuell laden:

gdb> symbol-datei libzathras-46703-64.so

Wenn Sie noch mehr Informationen möchten, können Sie Ihren c/C++ - Code mit aktivierten Debug-Informationen kompilieren. Im Allgemeinen fügen Sie mit dem mingw- und gcc-Compiler den Befehlszeilenoptionen -g hinzu. Dadurch erhalten Sie die folgenden Informationen, die Zeilennummern und so enthält.

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

auch, vergessen Sie nicht, Sie können 'addr2line' mit der Adresse aus dem Dump verwenden, um die genaue Codezeile zu erhalten, die das Problem verursacht. – Shark

Verwandte Themen