it-swarm-es.tech

¿Cómo chocar una JVM?

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

¿Alguien tiene alguna idea?

140
Shivasubramanian A

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

5
Leigh Caldwell

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

  1. Usa JNI y cuelga 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 VM específico, pero normalmente un VM almacena un montón de punteros a recursos nativos en campos privados (por ejemplo, un puntero al objeto de subproceso nativo se almacena en un campo largo en Java.lang.Thread ). Simplemente cámbielos a través de la reflexión y el VM se bloqueará tarde o temprano.
  3. Todas las máquinas virtuales tienen errores, así que solo tienes que activar uno.

Para el último método, tengo un breve ejemplo, que bloqueará un punto de acceso de Sun VM tranquilamente:

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 el GC, por lo que no obtendrá StackOverflowError sino un bloqueo real que incluye un archivo hs_err *.

171
ralfs

JNI . De hecho, con JNI, el bloqueo es el modo de operación predeterminado. Tienes que trabajar más duro para que no se bloquee.

122
Dan Dyer

Utilizar 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 clase de inicio porque está usando un código de confianza, por lo tanto, ejecute así:

Java -Xbootclasspath/p :. Choque

55
Dave Griffiths

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

Específicamente, pregunta:

¿Cómo escribiría un programa, en Java puro, que haría que la Máquina Virtual de Java se bloquee?

He programado en Java por más de 15 años, y encontré que esta pregunta es a la vez desconcertante e injusta. Como han señalado otros, Java, como lenguaje gestionado, está diseñado específicamente para que no se bloquee. 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. Es probable que se solucione algún error de este tipo en la próxima versión, así que, ¿cuál es la probabilidad de que, como programador, se tope con y recuerde los detalles del conjunto actual de bloqueadores de JRE?

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 eso está fuera.

Otra opción sería alimentar los códigos de bytes falsos de JRE; es bastante fácil volcar algunos datos binarios de basura en un archivo .class y pedirle al JRE que lo ejecute:

$ 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 volar la pila a través de la recursión, quedarse sin memoria de pila a través de asignaciones de objetos, o simplemente lanzar RuntimeException. Pero esto solo hace que el JRE salga con una StackOverflowError o una excepción similar, que nuevamente no es realmente un fallo.

Entonces, ¿qué queda? Me encantaría escuchar lo que el autor realmente tenía en mente como una solución adecuada.

Actualización : Chad Fowler respondió aquí .

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

31
George Armhold

Este código colapsará la JVM de manera desagradable

import Sun.dc.pr.PathDasher; 

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

La última vez que lo intenté 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
17
Hot Licks

Una perfecta implementación de JVM nunca fallará.

Para bloquear una JVM, además de JNI, debe encontrar un error en el VM. Un bucle infinito solo consume CPU. La asignación infinita de memoria debería causar que OutOfMemoryError's esté en una JVM bien construida. Esto probablemente causaría problemas en otros subprocesos, pero una buena JVM no debería fallar.

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

14
Dave L.

Si desea bloquear JVM, use lo siguiente en Sun JDK 1.6_23 o inferior:

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

Esto se debe a un error en Sun JDK - también encontrado en OpenJDK. Esto se soluciona a partir de Oracle JDK 1.6_24 en adelante.

13

Depende de lo que quieres decir con accidente.

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

También puede usar JNI para llamar código nativo. Si no lo haces bien, entonces puedes hacer que choque con fuerza. Depurar esos bloqueos es "divertido" (créeme, tuve que escribir un gran C++ DLL que llamamos desde un applet de Java firmado). :)

10
Herms

El libro Java Virtual Machine por Jon Meyer tiene un ejemplo de una serie de instrucciones de bytecode que causaron que el JVM se dumpese en el núcleo. No puedo encontrar mi copia de este libro. Si alguien tiene uno, por favor búscalo y publica la respuesta.

6
Soulfly

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 memoria RAM defectuosa.

5

No es un choque, pero está más cerca de un choque que la respuesta aceptada de usar System.exit

Puedes detener la JVM llamando

Runtime.getRuntime().halt( status )

Según los documentos:

"este método no hace que se inicien los enganches de cierre y no se ejecutan los finalizadores no invocados si se ha habilitado la finalización en la salida".

5
henry

camino más corto posible :)

public class Crash
{
    public static void main(String[] args)
    {
        main(args);
    }
}
5
RRM

en winxpsp2 w/wmp10 jre6.0_7

Desktop.open (uriToAviOrMpgFile)

Esto hace que un hilo generado genere un Throwable no cosechado y se cuelgue un hotspot

YMMV

5
kitsuneymg

Si define una falla como un proceso abortado debido a una situación no controlada (es decir, sin excepción o error de Java), 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.

Las fallas típicas en el código nativo ocurren al quitar la referencia de los punteros a las áreas de memoria incorrecta (dirección nula o desalineada). Otra fuente podría ser instrucciones de máquina ilegales (códigos de operación) o señales no manejadas desde 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 tener problemas que conducen a bloqueos reales (era bastante común que se produjera un bloqueo cuando usaba las funciones Zip y se quedaban sin memoria). En esos casos, el manejador de fallas de la JVM inicia y descarga el estado. También podría generar un archivo principal del sistema operativo (Dr. Watson en Windows y volcado de 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 Hotspot captura esta señal y la vuelve a lanzar como una NullPointerException en la mayoría de los lugares. Así que es mejor enviar una SIGBUS por ejemplo.

4
eckes

aquí hay una explicación detallada sobre las causas por las que JVM se vuelca en el núcleo (es decir, falla): http://kb.Adobe.com/selfservice/viewContent.do?externalId=tn_17534

4
COTOHA

Si quieres fingir que te has quedado sin memoria, puedes hacerlo.

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

Conozco un par de maneras de hacer que JVM voltee un archivo de error llamando a métodos nativos (aquellos que están integrados), pero probablemente sea mejor que no sepa cómo hacerlo. ;)

3
Peter Lawrey

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

3
Jared

Si creas un proceso de subprocesos que genera infinitamente más subprocesos (que generan más subprocesos, que ...) eventualmente causará un error de desbordamiento de pila en la 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, mira tu carnero)

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:
# 
2
Lightfire228

Más corto? Utilice la clase de robot para activar CTRL + BREAK. Descubrí esto cuando intentaba cerrar mi programa sin cerrar la consola (no tenía la funcionalidad 'salir').

1
user6022288

Lo estoy haciendo ahora, pero no estoy completamente seguro de cómo ... :-) JVM (y mi aplicación) a veces simplemente desaparecen por completo. No se lanzan errores, no se registra nada. Pasa de funcionar a no ejecutarse al instante sin aviso.

0
Brian Knoblauch

¿Esto cuenta?

long pid = ProcessHandle.current().pid();
try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}

Solo funciona para Linux y desde Java 9.

Por alguna razón no entiendo, ProcessHandle.current().destroyForcibly(); no mata a la JVM y lanza Java.lang.IllegalStateException con el mensaje destruir el proceso actual no permitido .

0
mszmurlo