java exit processbuilder

¿Qué puede hacer que Java siga ejecutándose después de System.exit()?



processbuilder (8)

El proceso principal tiene un subproceso dedicado a consumir cada uno de los STDOUT y STDERR del niño (que pasa esa salida a un archivo de registro). Por lo que puedo ver, funcionan correctamente, ya que estamos viendo todos los resultados que esperamos ver en el registro

Tuve un problema similar con mi programa que no desaparecía de la gestión de tareas cuando estaba consumiendo stdout / stderr. en mi caso, si cerraba el flujo que escuchaba antes de llamar a system.exit (), entonces el javaw.exe se quedaba. extraño, no estaba escribiendo a la corriente ...

La solución en mi caso era simplemente vaciar la corriente en lugar de cerrarla antes de existir. por supuesto, siempre se puede vaciar y luego redireccionar a stdout y stderr antes de salir.

Tengo un programa Java que se está iniciando a través de ProcessBuilder desde otro programa Java. System.exit(0) desde el programa hijo, pero para algunos de nuestros usuarios (en Windows) el proceso java.exe asociado con el hijo no finaliza. El programa hijo no tiene ganchos de apagado, ni tiene un SecurityManager que podría impedir que System.exit() termine la máquina virtual. No puedo reproducir el problema yo mismo en Linux o Windows Vista. Hasta ahora, los únicos informes del problema provienen de dos usuarios de Windows XP y uno de Vista, que usan dos JRE diferentes (1.6.0_15 y 1.6.0_18), pero pueden reproducir el problema cada vez.

¿Alguien puede sugerir razones por las cuales la JVM no terminaría después de System.exit() , y solo en algunas máquinas?

Edición 1: el usuario instaló el JDK para que podamos obtener un volcado de subprocesos de la máquina virtual ofensiva. Lo que me dijo el usuario es que el proceso de VM desaparece de VisualVM en cuanto hace clic en el elemento ''Salir'' de mi menú, pero, según el Administrador de tareas de Windows, el proceso no ha finalizado, y no importa cuánto tiempo. El usuario espera (minutos, horas), nunca termina.

Edición 2: He confirmado ahora que Process.waitFor() en el programa principal nunca regresa para al menos uno de los usuarios que tiene el problema. Entonces, para resumir: la VM secundaria parece estar muerta (VisualVM ni siquiera la ve), pero la matriz aún ve el proceso como activo y también lo hace Windows.


¿El proceso principal consume el error y la secuencia de salida del proceso secundario? Si bajo algún sistema operativo, el proceso infantil imprime algunos errores / advertencias en stdout / stderr y el proceso principal no está consumiendo los flujos, el proceso infantil se bloqueará y no llegará a System.exit ();


Aquí hay un par de escenarios ...

Según la definición de un tema en http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.html

...

Cuando se inicia una máquina virtual Java, generalmente hay un único hilo no daemon (que normalmente llama al método denominado main de alguna clase designada). La máquina virtual de Java continúa ejecutando subprocesos hasta que ocurra cualquiera de las siguientes situaciones:

1) Se ha llamado al método de salida de la clase Runtime y el administrador de seguridad ha permitido que se lleve a cabo la operación de salida. 2) Todos los subprocesos que no son daemon han muerto, ya sea volviendo de la llamada al método de ejecución o lanzando una excepción que se propaga más allá del método de ejecución.

Otra posibilidad es si se ha llamado al método runFinalizersOnExit. según la documentación en http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html desuso. Este método es inherentemente inseguro. Puede hacer que se llame a los finalizadores en objetos vivos mientras que otros subprocesos manipulan esos objetos simultáneamente, lo que resulta en un comportamiento errático o un punto muerto. Habilitar o deshabilitar la finalización en la salida; al hacerlo, se especifica que los finalizadores de todos los objetos que tienen finalizadores que aún no se han invocado automáticamente deben ejecutarse antes de que se cierre el tiempo de ejecución de Java. Por defecto, la finalización en la salida está deshabilitada. Si hay un administrador de seguridad, primero se llama a su método checkExit con 0 como argumento para garantizar que se permita la salida. Esto podría resultar en una excepción de seguridad.


Creo que todas las causas obvias han sido cubiertas provisionalmente; por ejemplo, los finalizadores, los ganchos de apagado, no drenan correctamente la salida estándar / error estándar en el proceso principal. Ahora necesita más pruebas para averiguar lo que está pasando.

Sugerencias:

  1. Configure una máquina con Windows XP o Vista (o virtual), instale el JRE relevante y su aplicación, e intente reproducir el problema. Una vez que pueda reproducir el problema, adjunte un depurador o envíe la señal correspondiente para obtener un volcado de hilo a un error estándar.

  2. Si no puede reproducir el problema como se indicó anteriormente, haga que uno de sus usuarios tome un volcado de hilos y le envíe el archivo de registro.


Esto puede suceder si su código (o la biblioteca que usa) tiene un gancho de apagado o un finalizador que no termina de forma limpia.

Una forma más vigorosa (¡por lo tanto, solo debe usarse en casos extremos!) Para forzar el apagado es ejecutando:

Runtime.getRuntime().halt(0);


Hy tuve el mismo problema, pero la razón para mí era que estaba usando la depuración remota (VmArgs: -Xdebug -Xrunjdwp: transporte = dt_socket, dirección =% puerto%, servidor = y, suspender = y) cuando deshabilité este java.exe El proceso salió como se esperaba.


Otro caso que no se menciona aquí es si los ganchos de cierre cuelgan de algo, así que tenga cuidado al escribir el código del gancho de cierre (y si una biblioteca de terceros registró un gancho de cierre que también se cuelga).

Decano


Tal vez un finalizador mal escrito? Un primer gancho fue lo primero que pensé cuando leí la línea del asunto. Especulación: ¿un subproceso que atrapa la excepción InterruptedException y continúa funcionando de todos modos detendría el proceso de salida?

Me parece que si el problema es reproducible, debería poder adjuntarlo a la JVM y obtener un seguimiento de la lista / pila de hilos que muestra lo que está colgado.

¿Estás seguro de que el niño todavía está corriendo y de que no se trata solo de un proceso zombie sin ser capturado?