2009-11-19 15 views
7

Mi aplicación es principalmente Java pero, para ciertos cálculos, usa una biblioteca C++. Nuestro entorno es Java 1.6 corriendo en RedHat 3 (que pronto será RedHat 5).¿Es posible depurar los volcados del núcleo al usar Java JNI?

Mi problema es que la biblioteca de C++ no es segura para subprocesos. Para evitar esto, ejecutamos múltiples procesos de "un solo trabajador" y les damos trabajo que hacer desde un Administrador de trabajo central, también escrito en C++. Nuestra aplicación Java llama al C++ Work Manager a través de un producto de terceros.

Por diversas razones, queremos volver a escribir el C++ Work Manager y los trabajadores. Estoy a favor de escribirlos todos en Java, usando JNI en cada trabajador para llamar a la biblioteca de C++.

El problema principal es qué ocurre si se vuelca el núcleo de la biblioteca C++. Desafortunadamente, esto es bastante común, y debemos poder ver qué línea de nuestra biblioteca C++ causó el problema, p. al examinar una traza inversa en algo como GDB.

Mis colegas creen que será imposible analizar los volcados del núcleo, porque las herramientas como GDB no entienden los archivos centrales producidos por Java.

Espero que estén equivocados, pero necesito estar seguro antes de continuar con mis ideas.

¿Cuál es la mejor manera de analizar un volcado de núcleo producido a partir de Java/JNI?

Respuesta

7

Sí, la hay. Cada vez que JVM se cuelga debido a un SIGSEGV en la parte JNI, obtendrá un archivo con el volcado del núcleo en el directorio $ JAVA_HOME/bin. Suele nombrar hs_err_PID.log.

Puede obtener más información here y here. Here es una pregunta de stackoverflow algo relacionada.

+2

Gracias Pablo. El artículo de kohsuke es excelente. Desafortunadamente, si les digo a mis colegas que necesitarán comprender al ensamblador para descubrir qué línea C++ causó la falla seg, se ejecutarán una milla. Estoy en Linux y mis archivos .so se han compilado con la marca de depuración activada. Tal vez esto hará que el proceso sea más fácil. –

+1

Lo sentimos, pero un archivo de 'registro' no tiene nada que ver con el coredump sobre el que se preguntó O.P. –

+0

Encontré estos archivos hs_err_PID en el directorio/tmp. – Aman

2

Para obtener el archivo core leído en gdb, debe agregar la máquina virtual java. Es decir

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

que sea muy probable que le dirá que una tonelada de símbolos no se encuentran (lo cual es normal, estos son los símbolos de JVM). Sin embargo, la llamada JNI que se estrelló podría aparecer en tu stacktrace si escribes 'bt'. Un ejemplo, en mi situación, en la que tengo un accidente en una biblioteca nativa escribí, es:

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

Los primeros 6 marcos están todos relacionados con el proceso de choque en sí. Una señal fue capturada y despachada. Y a pesar de que no conocemos las funciones exactas, no importa. Comenzando en el cuadro 7, estamos en la biblioteca JNI que escribimos. Y si todavía tiene símbolos adjuntos, los verá.

#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 

Y desde el cuadro 14 en adelante estamos de vuelta en la tierra de 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 

para que veas que no es completamente imposible conseguir algo de información de los archivos del núcleo a través del BGF. Simplemente no olvides agregar el jvm como primer argumento.

Es posible que gdb no encuentre la biblioteca nativa en sí. En ese caso, es posible que desee cargar los símbolos manualmente de la siguiente manera:

gdb> archivo-símbolo libzathras-46703-64.así que

Si desea obtener aún más información, es posible que desee compilar su código c/C++ con la información de depuración activada. En general, con el compilador mingw y gcc agrega a -g a las opciones de la línea de comando. Esto le proporcionará la siguiente información, que incluye los números de línea y así sucesivamente.

#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

también, no olvide que puede usar 'addr2line' con la dirección del volcado para obtener la línea exacta de código que causa el problema. – Shark

Cuestiones relacionadas