2008-09-15 15 views
114

Estaba leyendo un libro sobre habilidades de programación en el que el autor pregunta al entrevistado: "¿Cómo se cuelga una JVM?" Pensé que podrías hacerlo escribiendo un bucle for infinito que eventualmente usaría toda la memoria.¿Cómo bloqueas una JVM?

¿Alguien tiene alguna idea?

+16

Apasionado programador, sí, gran libro;) – dolzenko

+1

superconjunto de Posible: http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java –

+0

https://stackoverflow.com/questions/30072883/java-swing-jwindow-application-crash "Si uso JDK1.8_40 o posterior (Oracle o OpenJDK do lo mismo), el siguiente código junto con un cambio de tamaño del cuadro de diálogo bloqueará la aplicación (se intentó con Windows 7, x64, JDK de 64 bits) ": el código tiene solo 40 líneas y causa un * bloqueo adecuado * de la JVM. –

Respuesta

6

Lo más parecido a una única "respuesta" es la que System.exit() termina la JVM inmediatamente sin una limpieza adecuada. Pero aparte de eso, el código nativo y el agotamiento de recursos son las respuestas más probables. Alternativamente, puede buscar errores en el rastreador de errores de Sun en su versión de la JVM, algunos de los cuales permiten escenarios de bloqueo repetibles. Solíamos tener bloqueos semi regulares cuando nos acercamos al límite de memoria de 4 Gb en las versiones de 32 bits (generalmente usamos 64 bits ahora).

+59

sin una limpieza adecuada? ¿Estás seguro? La documentación dice "Termina la máquina virtual Java actualmente en ejecución iniciando su secuencia de apagado ... todos los enganches de cierre registrados, si los hay, se inician ... se ejecutan todos los finalizadores no invocados" - ¿no es esa la limpieza adecuada? –

+46

Esto no está bloqueando la JVM, sino que de forma intencionada y explícita comienza un cierre ordenado de la ejecución. – BenM

+8

Más cerca de bloquear el jvm es Runtime.getRuntime(). Detener (estado). De acuerdo con los documentos "este método no provoca el inicio de los ganchos de cierre y no ejecuta los finalizadores no invocados si se ha habilitado la finalización a la salida". Todavía no es un bloqueo, pero está más cerca que System.exit. – henry

114

JNI. De hecho, con JNI, el bloqueo es el modo de operación predeterminado. Tienes que trabajar muy duro para que no se cuelgue.

+49

+1 "con JNI, estrellarse es el modo de operación predeterminado" ¡Genial, y muy cierto! –

+5

* Bigbadaboom * !! –

+2

Tal vez los diseñadores de JNI habían oído hablar de [software solo de bloqueo] (http://en.wikipedia.org/wiki/Crash-only_software), pero aún no habían captado la idea. –

9

Depende de lo que quiere decir crash.

Puede hacer una recursión infinita para que se quede sin espacio de pila, pero se bloqueará "con gracia". Obtendrá una excepción, pero la propia JVM se encargará de todo.

También puede usar JNI para llamar al código nativo. Si no lo haces de manera correcta, puedes hacer que se estrelle. La depuración de esos bloqueos es "divertida" (confía en mí, tuve que escribir una gran DLL de C++ que llamamos desde un applet Java firmado). :)

-1

Si cambia esa infinita para el lazo a una llamada recursiva a la misma función, entonces se podrían obtener una excepción de desbordamiento de pila:

public static void main(String[] args) { 
    causeStackOverflow(); 
} 

public void causeStackOverflow() { 
    causeStackOverflow(); 
} 
12

Una implementación perfecta de JVM nunca se bloqueará.

Para colgar una JVM, además de JNI, necesita encontrar un error en la máquina virtual. Un bucle infinito solo consume CPU. La asignación infinita de memoria solo debería causar OutOfMemoryError en una JVM bien construida. Esto probablemente causaría problemas para otros subprocesos, pero una buena JVM aún no debería fallar.

Si puede encontrar un error en el código fuente de la máquina virtual y, por ejemplo, causa un error de segmentación en el uso de la memoria de la implementación de la máquina virtual, entonces puede bloquearla.

5

El libro Java Virtual Machine de Jon Meyer tiene un ejemplo de una serie de instrucciones de bytecode que hicieron que la JVM se volcara al núcleo. No puedo encontrar mi copia de este libro. Si alguien tiene uno, búsquelo y publique la respuesta.

157

No llamaría a un lanzamiento de OutOfMemoryError o StackOverflowError. Estas son solo excepciones normales. Para bloquear realmente una VM hay 3 formas:

  1. Usa JNI y crash en el código nativo.
  2. Si no hay un administrador de seguridad instalado, puede usar la reflexión para bloquear la máquina virtual. Esto es específico de VM, pero normalmente una VM almacena un grupo de punteros a recursos nativos en campos privados (por ejemplo, un puntero al objeto de hilo nativo se almacena en un campo largo en java.lang.Thread). Simplemente cámbialos a través de la reflexión y la máquina virtual se bloqueará tarde o temprano.
  3. Todas las máquinas virtuales tienen errores, por lo que solo tiene que activar una.

Para el último método Tengo un pequeño ejemplo, que se colgará una tranquila Sun Hotspot VM muy bien:

public class Crash { 
    public static void main(String[] args) { 
     Object[] o = null; 

     while (true) { 
      o = new Object[] {o}; 
     } 
    } 
} 

Esto conduce a un desbordamiento de pila en la general por lo que obtendrá ningún StackOverflowError sino una bloqueo real que incluye un archivo hs_err *.

+8

Suena como un GC muy roto ... – leppie

+7

¡Guau!Esto bloquea Sun Java 5, Sun Java 6 y OpenJDK 6 (en Ubuntu 9.04) sin ningún archivo hs_err * pero solo un "¡Error de segmentación!" ... –

+0

System.exit() es una forma mucho más fácil de bloquear una JVM (a menos que esté instalado un administrador de seguridad) – instantsetsuna

4

Si define un bloqueo como un aborto de proceso debido a una situación no controlada (es decir, sin excepción Java o error), esto no se puede hacer desde Java (a menos que tenga permiso para usar la clase sun.misc.Unsafe) Este es todo el punto del código administrado.

Los bloqueos típicos en el código nativo ocurren al desviar referencias a áreas de memoria incorrectas (dirección nula o mal alineadas). Otra fuente podría ser instrucciones de máquinas ilegales (códigos de operación) o señales no controladas de la biblioteca o llamadas al kernel. Ambos pueden activarse si la JVM o las bibliotecas del sistema tienen errores.

Por ejemplo, el código JITed (generado), los métodos nativos o las llamadas al sistema (controlador de gráficos) pueden causar problemas y provocar bloqueos reales (era bastante común tener un bloqueo cuando usaba funciones ZIP y se quedaba sin memoria). En esos casos, el controlador de bloqueo de la JVM entra en acción y vuelca el estado. También podría generar un archivo de núcleo del sistema operativo (Dr. Watson en Windows y volcado del núcleo en * nix).

En Linux/Unix puede realizar fácilmente un bloqueo de JVM enviándole una señal al proceso en ejecución. Nota: no debe usar SIGSEGV para esto, ya que el Hotspot capta esta señal y la vuelve a lanzar como NullPointerException en la mayoría de los lugares. Por lo tanto, es mejor enviar un SIGBUS por ejemplo.

5

en WinXPSP2 w/WMP10 jre6.0_7

Desktop.open (uriToAviOrMpgFile)

Esto provoca un subproceso generado para lanzar un Throwable no detectada y se estrella hotspot

YMMV

0

Lo estoy haciendo ahora, pero no del todo seguro de cómo ... :-) JVM (y mi aplicación) a veces simplemente desaparecen por completo. Sin errores lanzados, nada registrado. Deja de funcionar para no funcionar en absoluto al instante sin previo aviso.

+0

¡Comience a verificar su hardware, especialmente su memoria! –

+0

Desafortunadamente, está en varias máquinas que de otra manera funcionan bien. Es solo esta aplicación en particular la que lo hace (y no requiere memoria o procesador). –

3

Si quieres pretender que haya quedado sin memoria que puede hacer

public static void main(String[] args) { 
    throw new OutOfmemoryError(); 
} 

Conozco a un par de manera de hacer que la JVM volcar un archivo de error llamando a métodos nativos (los que se construyen en) , pero probablemente sea mejor que no sepas cómo hacer esto. ;)

3

JNI es una gran fuente de bloqueos. También puede bloquearse utilizando la interfaz JVMTI, ya que también debe escribirse en C/C++.

5

El hardware roto puede bloquear cualquier programa. Una vez tuve un bloqueo de la aplicación reproducible en una máquina específica mientras funcionaba bien en otras máquinas con la misma configuración. Resulta que la máquina tenía RAM defectuosa.

49

Utilice esta:

import sun.misc.Unsafe; 

public class Crash { 
    private static final Unsafe unsafe = Unsafe.getUnsafe(); 
    public static void crash() { 
     unsafe.putAddress(0, 0); 
    } 
    public static void main(String[] args) { 
     crash(); 
    } 
} 

Esta clase debe estar en la ruta de clases de arranque porque está utilizando el código de confianza, por lo que ejecutar la siguiente manera:

java -Xbootclasspath/p:. Crash

+11

En lugar de utilizar -Xbootclasspath también puede hacer esto: 'Campo f = Unsafe.class.getDeclaredField (" theUnsafe "); f.setAccessible (verdadero); inseguro = (Inseguro) f.get (null); 'Funcionó muy bien para mí. – pushy

+0

'Inseguro' es, por definición," inseguro ". Esto es un poco trampa. –

+1

Se confirmó que funciona utilizando el truco 'getDeclaredField' en JDK 8u131 en Linux x64, incluida la producción de' hs_err_pid * .log' de un 'SIGSEGV'. –

18

Este código se bloqueará la JVM en formas desagradables

import sun.dc.pr.PathDasher; 

public class Crash 
{ 
    public static void main(String[] args) 
    {  
     PathDasher dasher = new PathDasher(null) ; 
    } 
} 
+4

a partir de 1.6.0_29 este es el único que funcionó para mí – Persimmonium

+1

Obteniendo error de compilación al usar JDK 1.7 con este código: ** Restricción de acceso: El tipo PathDasher no es accesible debido a la restricción en la biblioteca requerida C: \ Program Files \ Java \ jdk1.7.0_51 \ jre \ lib \ rt.jar ** – realPK

+5

Esto arroja un 'InternalError' en JDK 1.8. JVM ya no falla. –

8

Si desea bloqueo de JVM - utilizar el siguiente en Sun JDK 1.6_23 o por debajo de:

Double.parseDouble("2.2250738585072012e-308"); 

Esto se debe a un bug en Sun JDK - también se encuentra en OpenJDK. Esto se soluciona desde Oracle JDK 1.6_24 en adelante.

28

Vine aquí porque también encontré esta pregunta en The Passionate Programmer, por Chad Fowler. Para aquellos que no tienen acceso a una copia, la pregunta se enmarca como una especie de filtro/prueba para los candidatos que se entrevistan para un puesto que requiere "muy buenos programadores de Java".

Específicamente, se pregunta:

How would you write a program, in pure Java, that would cause the Java Virtual Machine to crash?

He programado en Java por más de 15 años, y me encontré con esta pregunta para ser a la vez desconcertante e injusta. Como han señalado otros, Java, como lenguaje administrado, está específicamente diseñado para no bloquear. Por supuesto, siempre hay errores de JVM, pero:

  1. Después de más de 15 años de JRE de nivel de producción, es raro.
  2. Cualquiera de estos errores es probable que se parcheen en la próxima versión, entonces, ¿qué tan probable es que usted como programador se tope y recuerde los detalles del conjunto actual de JRE show-stoppers?

Como han mencionado otros, algunos códigos nativos a través de JNI son una forma segura de bloquear un JRE. Pero el autor mencionó específicamente en Java puro, así que está fuera.

Otra opción sería alimentar los códigos de byte falsos de JRE; que es bastante fácil para volcar algunos datos binarios de basura en un archivo .class, y pedir el JRE para ejecutarlo:

$ echo 'crap crap crap' > crap.class 
$ java crap 
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1668440432 in class file crap 

¿eso cuenta? Quiero decir que el JRE en sí no se ha estrellado; detectó correctamente el código falso, lo informó y salió.

Esto nos deja con los tipos más obvios de soluciones como soplar la pila por recursión, quedarse sin memoria del montón a través de asignaciones de objetos o simplemente lanzar RuntimeException. Pero esto solo hace que JRE salga con una excepción StackOverflowError o similar, que, de nuevo, no es realmente una falla.

¿Qué queda? Realmente me encantaría escuchar lo que el autor realmente tenía en mente como una solución adecuada.

Actualización: Chad Fowler responded here.

PD: es un gran libro por lo demás. Lo recogí para obtener apoyo moral mientras aprendía Ruby.

+1

Tales preguntas de entrevista sirven como pruebas de fuego para los desarrolladores de Java que han existido lo suficiente como para 1) haber presenciado (muchos) bloqueos de JVM y 2) haber sacado algunas conclusiones o, mejor aún, como (autoproclamados) los expertos de Java han intentado comprender las razones subyacentes de un bloqueo. Chad Fowler también afirma en su libro que los autoproclamados programadores de Java "ni siquiera pueden dar con la respuesta incorrecta", es decir, no han intentado pensar cuándo una clase completa de problemas potenciales. La conclusión: esta pregunta es segway a "¿Cómo prevenir los bloqueos de JVM?" que es claramente aún mejor saber. – Shonzilla

+1

Buscaría a las personas que acaban de responder (como la mayoría aquí) "desbordan la pila", system.exit(), u otro cierre "Normal" ya que realmente no entienden la JVM o la palabra "Crash". Reconocer (como lo hiciste) que esto es muy anormal es una forma bastante buena de identificar a un programador más avanzado. Estoy de acuerdo con su primera declaración, me parece una pregunta excelente y totalmente justa para hacer o preguntar: los que no tienen respuestas concretas siempre son los mejores. –

4

camino más corto posible :)

public class Crash 
{ 
    public static void main(String[] args) 
    { 
     main(args); 
    } 
} 
+0

No falla. Da el error de tiempo de compilación 'Exception in thread" main "java.lang.StackOverflowError at Test.main'. Estoy usando jdk1.8.0_65 –

14

La última vez que probé este lo haría:

public class Recur { 
    public static void main(String[] argv) { 
     try { 
      recur(); 
     } 
     catch (Error e) { 
      System.out.println(e.toString()); 
     } 
     System.out.println("Ended normally"); 
    } 
    static void recur() { 
     Object[] o = null; 
     try { 
      while(true) { 
       Object[] newO = new Object[1]; 
       newO[0] = o; 
       o = newO; 
      } 
     } 
     finally { 
      recur(); 
     } 
    } 
} 

Primera parte del archivo de registro generado:

# 
# An unexpected error has been detected by Java Runtime Environment: 
# 
# EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x000000006dad5c3d, pid=6752, tid=1996 
# 
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.2-b01 mixed mode windows-amd64) 
# Problematic frame: 
# V [jvm.dll+0x2e5c3d] 
# 
# If you would like to submit a bug report, please visit: 
# http://java.sun.com/webapps/bugreport/crash.jsp 
# 

--------------- T H R E A D --------------- 

Current thread (0x00000000014c6000): VMThread [stack: 0x0000000049810000,0x0000000049910000] [id=1996] 

siginfo: ExceptionCode=0xc00000fd, ExceptionInformation=0x0000000000000001 0x0000000049813fe8 

Registers: 
EAX=0x000000006dc83090, EBX=0x000000003680f400, ECX=0x0000000005d40ce8, EDX=0x000000003680f400 
ESP=0x0000000049813ff0, EBP=0x00000000013f2df0, ESI=0x00000000013f0e40, EDI=0x000000003680f400 
EIP=0x000000006dad5c3d, EFLAGS=0x0000000000010206 
+0

Estoy un poco entretenido con la votación negativa, dado que esta es una de las dos únicas respuestas que muestran cómo hacerlo puramente con código Java, e incluye el código completo. –

+0

Estoy de acuerdo en que no se justifica un voto a la baja: se trata de una verdadera caída, pero ¿cómo respondería usted a la pregunta de la entrevista? A menos que haya investigado previamente y memorizado esto, no podría darlo como respuesta en la entrevista y, si pudiera, consideraría una respuesta de neutral a pobre, de todos modos, no muestra cómo abordaría el problema. Espero que lo que hiciste fue google para jvm bug exploits e implemente uno que es una excelente respuesta. –

+0

@BillK - No, lo anterior es completamente mi propio trabajo, aunque se me ocurrió hace varios años, experimentando con varias cosas. En una entrevista, probablemente diría "Lo he hecho, usando try/catch y recursión, pero no puedo contar el código exacto en este momento." –

0

Si un 'Crash 'es cualquier cosa que interrumpe el programa jvm/de la terminación normal, entonces una excepción sin manejo podría hacer esto.

public static void main(String args[]){ 
    int i = 1/0; 
    System.out.print(i); // This part will not be executed due to above unhandled exception 
    } 

Por lo tanto, depende de qué tipo de CRASH?!

+2

Lanzar una excepción no es un bloqueo. –

+0

U Las excepciones de tiempo de ejecución manipuladas son bloqueos, sin embargo, que 'ArithmeticException' es – Midnightas

4
No

un accidente, pero más cerca de un accidente que la respuesta aceptada de utilizar System.exit

Puede detener la JVM llamando

Runtime.getRuntime().halt(status)

De acuerdo con los documentos: -

"this method does not cause shutdown hooks to be started and does not run uninvoked finalizers if finalization-on-exit has been enabled".

+0

Esta es la mejor respuesta de la API. Lo uso para auditorías. – hiergiltdiestfu

0

¿Más corto? Usa la clase Robot para disparar CTRL + BREAK. Vi esto cuando estaba tratando de cerrar mi programa sin cerrar la consola (no tenía la funcionalidad de 'salir').

+0

Pregunta anterior: es de esperar que alguien se beneficie de su respuesta en el futuro. – dbmitch

0

Si crea un proceso de subproceso que genere infinitamente más subprocesos (que generen más subprocesos, lo que ...) eventualmente causará un error de desbordamiento de pila en la propia JVM.

public class Crash { 
    public static void main(String[] args) { 

     Runnable[] arr = new Runnable[1]; 
     arr[0] =() -> { 

      while (true) { 
       new Thread(arr[0]).start(); 
      } 
     }; 

     arr[0].run(); 
    } 
} 

Esto me dio la salida (después de 5 minutos, el reloj de la memoria RAM)

An unrecoverable stack overflow has occurred. 
# 
# A fatal error has been detected by the Java Runtime Environment: 
# 
# EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x0000000070e53ed7, pid=12840, tid=0x0000000000101078 
# 
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01) 
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode windows-amd64 compressed oops) 
# Problematic frame: 
#