2009-11-19 11 views
7

La mia applicazione è principalmente Java ma, per determinati calcoli, utilizza una libreria C++. Il nostro ambiente è Java 1.6 in esecuzione su RedHat 3 (che presto diventerà RedHat 5).È possibile eseguire il debug di core dump quando si utilizza Java JNI?

Il mio problema è che la libreria C++ non è thread-safe. Per ovviare a questo, eseguiamo più processi "worker" a thread singolo e offriamo loro il lavoro da fare da un Work Manager centrale, anch'esso scritto in C++. La nostra applicazione Java chiama C++ Work Manager tramite un prodotto di terze parti.

Per vari motivi, desideriamo riscrivere il C++ Work Manager e gli addetti. Sono favorevole a scriverle tutte in Java, usando JNI in ogni worker per chiamare la libreria C++.

Il problema principale è che cosa succede se i dump core della libreria C++. Sfortunatamente, questo è abbastanza comune, e dobbiamo essere in grado di vedere quale linea nella nostra libreria C++ ha causato il problema, ad es. esaminando un backtrace in qualcosa come GDB.

I miei colleghi ritengono che sia impossibile analizzare i core dump, perché strumenti come GDB non comprendono i file core prodotti da Java.

Spero che abbiano torto, ma devo essere sicuro prima di spingere oltre le mie idee.

Qual è il modo migliore per analizzare un core dump prodotto da Java/JNI?

risposta

7

Sì, c'è. Ogni volta che JVM si arresta a causa di un SIGSEGV nella parte JNI, si ottiene un file con dump principale nella directory $ JAVA_HOME/bin. Solitamente si chiama hs_err_PID.log.

È possibile ottenere ulteriori informazioni here e here. Here è una domanda di stackoverflow in qualche modo correlata.

+2

Grazie Pablo. L'articolo di kohsuke è eccellente. Sfortunatamente, se dico ai miei colleghi che dovranno capire l'assemblatore per scoprire quale linea C++ ha causato l'errore seg, correranno per un miglio. Sono su Linux e i miei file .so sono stati compilati con il flag di debug attivato. Forse questo renderà il processo più facile. –

+1

Siamo spiacenti, ma un file 'log' non ha nulla a che fare con il coredump di cui O.P ha chiesto informazioni. –

+0

Ho trovato questi file hs_err_PID nella directory/tmp. – Aman

2

Per leggere il file core in gdb, è necessario aggiungervi la macchina virtuale java. Questo è

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

che verrà molto probabilmente vi dirà che una tonnellata di simboli non si trovano (che è normale, questi sono i simboli JVM). Tuttavia, la chiamata JNI che si è arrestata in modo anomalo potrebbe comparire nello stacktrace se si digita "bt". Un esempio, nella mia situazione, dove ho un incidente in una libreria nativa che ho scritto, è:

(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> 

I primi 6 fotogrammi sono tutti legati al processo di incidente stesso. Un segnale è stato catturato e inviato. E anche se non conosciamo le funzioni esatte, non importa. A partire dal frame 7, siamo nella libreria JNI che abbiamo scritto. E se avesse ancora i simboli collegati li vedrai.

#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 

E dal fotogramma 14 in poi siamo di nuovo in terra 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 

Quindi si vede che non è completamente impossibile ottenere alcune informazioni dai file principali tramite gdb. Non dimenticare di aggiungere il jvm come primo argomento ad esso.

È possibile che gdb non trovi la stessa libreria nativa. In tal caso, è possibile caricare manualmente i simboli come segue:

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

Se si desiderano ulteriori informazioni, è possibile che si desideri compilare il codice c/C++ con le informazioni di debug attivate. Generalmente con il compilatore mingw e gcc si aggiunge un -g alle opzioni della riga di comando. Questo ti fornirà le seguenti informazioni, che includono i numeri di riga e così via.

#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 (
    this=[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

Inoltre, non dimenticare che puoi usare 'addr2line' con l'indirizzo dal dump per ottenere l'esatta riga di codice che causa il problema. – Shark

Problemi correlati