it-swarm.it

Come si blocca una JVM?

Stavo leggendo un libro sulle capacità di programmazione in cui l'autore chiede all'intervistato "Come si fa a mandare in crash una JVM?" Ho pensato che potevi farlo scrivendo un infinito for-loop che alla fine avrebbe esaurito tutta la memoria.

Qualcuno ha qualche idea?

141

La cosa più vicina a una singola "risposta" è System.exit() che termina immediatamente la JVM senza un'adeguata pulizia. Ma a parte questo, il codice nativo e l'esaurimento delle risorse sono le risposte più probabili. In alternativa, puoi cercare il bug tracker di Sun nella tua versione di JVM, alcuni dei quali consentono scenari di crash ripetibili. Avevamo problemi di crash semi-regolari quando ci si avvicinava al limite di memoria da 4 Gb nelle versioni a 32 bit (ora usiamo generalmente 64 bit).

6
Leigh Caldwell

Non chiamerei il lancio di un OutOfMemoryError o StackOverflowError un arresto anomalo. Queste sono solo normali eccezioni. Per arrestare veramente a VM ci sono 3 modi:

  1. Usa JNI e blocca il codice nativo.
  2. Se non è installato alcun gestore della sicurezza, è possibile utilizzare reflection per arrestare in modo anomalo la VM. Questo è VM specifico, ma normalmente a VM memorizza un gruppo di puntatori a risorse native in campi privati ​​(ad es. Un puntatore all'oggetto thread nativo è archiviato in un lungo campo in Java.lang.Thread). Basta cambiarli tramite reflection e il VM andrà in crash prima o poi.
  3. Tutte le macchine virtuali hanno dei bug, quindi devi solo attivarne uno.

Per l'ultimo metodo ho un breve esempio, che causerà l'arresto anomalo di un Sun Hotspot VM silenziosamente bene:

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

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

Questo porta ad un overflow dello stack nel GC in modo da non ottenere StackOverflowError ma un vero arresto che include un file hs_err *.

172
ralfs

[~ ~ #] jni [~ ~ #] . In effetti, con JNI, l'arresto anomalo è la modalità operativa predefinita. Devi lavorare molto per far sì che non si blocchi.

123
Dan Dyer

Usa questo:

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();
    }
}

Questa classe deve trovarsi sul percorso di classe di avvio perché utilizza un codice attendibile, quindi esegui in questo modo:

Java -Xbootclasspath/p :. schianto

56
Dave Griffiths

Sono venuto qui perché ho anche incontrato questa domanda in The Passionate Programmer , di Chad Fowler. Per coloro che non hanno accesso a una copia, la domanda è inquadrata come una sorta di filtro/test per i candidati che intervistano per una posizione che richiede "davvero buono Java".

In particolare, chiede:

Come scriveresti un programma, in puro Java, che causerebbe l'arresto anomalo di Java Virtual Machine?

Ho programmato in Java per oltre 15 anni e ho trovato questa domanda sia sconcertante che ingiusta. Come altri hanno sottolineato, Java, come linguaggio gestito, è specificamente progettato non andare in crash. Ovviamente ci sono sempre bug di JVM, ma:

  1. Dopo oltre 15 anni di JRE a livello di produzione, è raro.
  2. È probabile che eventuali bug di questo tipo vengano corretti nella prossima versione, quindi con quale probabilità sei un programmatore per imbatterti e ricordare i dettagli dell'attuale serie di show-stopper di JRE?

Come altri hanno già detto, alcuni codici nativi tramite JNI sono un modo sicuro per arrestare un JRE. Ma l'autore ha menzionato in modo specifico in puro Java, quindi è uscito.

Un'altra opzione sarebbe quella di alimentare i codici byte fasulli JRE; è abbastanza facile scaricare alcuni dati binari dell'immondizia in un file .class e chiedere a JRE di eseguirlo:

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

Questo conta? Voglio dire, il JRE stesso non si è schiantato; ha correttamente rilevato il codice falso, lo ha segnalato ed è uscito.

Questo ci lascia con i tipi più ovvi di soluzioni come far esplodere lo stack tramite ricorsione, esaurire la memoria dell'heap tramite allocazioni di oggetti o semplicemente lanciare RuntimeException. Ma questo fa semplicemente uscire il JRE con una StackOverflowError o un'eccezione simile, che, di nuovo non è proprio un crash.

Quindi cosa rimane? Mi piacerebbe davvero sapere cosa aveva in mente l'autore come una soluzione adeguata.

Aggiornamento : Chad Fowler ha risposto qui .

PS: è un libro altrimenti fantastico. L'ho raccolto per supporto morale mentre imparavo Ruby.

32
George Armhold

Questo codice bloccherà la JVM in modi cattivi

import Sun.dc.pr.PathDasher; 

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

L'ultima volta che ho provato questo lo avrebbe fatto:

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();
        }
    }
}

Prima parte del file di registro generato:

#
# 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 perfetta implementazione JVM non si arresterà mai.

Per interrompere un JVM, a parte JNI, è necessario trovare un bug in VM stesso. Un ciclo infinito consuma solo CPU. Allocare in modo continuo la memoria dovrebbe causare OutOfMemoryError in un JVM ben costruito. probabilmente causerebbe problemi per altri thread, ma una buona JVM non dovrebbe comunque bloccarsi.

Se è possibile trovare un bug nel codice sorgente della VM e, ad esempio, causare un errore di segmentazione nell'utilizzo della memoria dell'implementazione della VM, è possibile arrestarlo effettivamente.

15
Dave L.

Se si desidera arrestare in modo anomalo JVM, utilizzare quanto segue in Sun JDK 1.6_23 o precedente:

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

Ciò è dovuto a bug in Sun JDK, presente anche in OpenJDK. Questo problema è stato risolto da Oracle JDK 1.6_24 in poi.

14

Dipende da cosa intendi per incidente.

Puoi fare una ricorsione infinita per farla esaurire lo spazio dello stack, ma si bloccherà "con grazia". Otterrai un'eccezione, ma la JVM stessa gestirà tutto.

Puoi anche usare JNI per chiamare il codice nativo. Se non lo fai nel modo giusto, puoi renderlo difficile. Il debug di questi arresti anomali è "divertente" (credetemi, ho dovuto scrivere un grande C++ DLL che chiamiamo da un'applet firmata Java). :)

10
Herms

Il libro Java Virtual Machine di Jon Meyer contiene un esempio di una serie di istruzioni bytecode che hanno causato il dump della JVM. Non riesco a trovare la mia copia di questo libro. Se qualcuno là fuori ne ha uno, per favore cercalo e pubblica la risposta.

6
Soulfly

L'hardware rotto può causare l'arresto anomalo di qualsiasi programma. Una volta ho avuto un crash dell'app riproducibile su una macchina specifica mentre funzionavo bene su altre macchine con la stessa configurazione. Si scopre che la macchina aveva RAM difettosa.

5

Non un arresto anomalo, ma più vicino a un arresto rispetto alla risposta accettata dell'utilizzo di System.exit

È possibile interrompere JVM chiamando

Runtime.getRuntime().halt( status )

Secondo i documenti: -

"questo metodo non provoca l'avvio di hook di chiusura e non esegue finalizzatori non invocati se la finalizzazione all'uscita è stata abilitata".

5
henry

il modo più breve possibile :)

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

su winxpsp2 con wmp10 jre6.0_7

Desktop.open (uriToAviOrMpgFile)

Questo fa sì che un thread generato generi un Throwable non catturato e si arresti in modo anomalo

YMMV

5
kitsuneymg

Se si definisce un arresto anomalo come interruzione di un processo a causa di una situazione non gestita (ovvero no Java Eccezione o errore), ciò non può essere fatto all'interno di Java (a meno che tu non abbia il permesso di usare la classe Sun.misc.Unsafe). Questo è l'intero punto del codice gestito.

Gli arresti anomali tipici nel codice nativo si verificano de-facendo riferimento a puntatori ad aree di memoria errate (indirizzo nullo o disallineato). Un'altra fonte potrebbe essere istruzioni macchina illegali (codici operativi) o segnali non gestiti dalle chiamate della libreria o del kernel. Entrambi possono essere attivati ​​se la JVM o le librerie di sistema presentano dei bug.

Ad esempio codice JITed (generato), metodi nativi o chiamate di sistema (driver di grafica) possono avere problemi che portano a veri e propri arresti anomali (era abbastanza comune ottenere un arresto anomalo quando si utilizzavano le funzioni Zip e rimanevano a corto di memoria). In questi casi il gestore di crash della JVM entra in azione e scarica lo stato. Potrebbe anche generare un file core del sistema operativo (Dr. Watson su Windows e core dump su * nix).

Su Linux/Unix è possibile effettuare facilmente un arresto anomalo della JVM inviandogli un segnale al processo in esecuzione. Nota: non dovresti usare SIGSEGV per questo, poiché Hotspot cattura questo segnale e lo re-lancia come NullPointerException nella maggior parte dei luoghi. Quindi è meglio inviare un SIGBUS per esempio.

4
eckes

ecco una spiegazione dettagliata di ciò che causa il core dump di JVM (ovvero crash): http://kb.Adobe.com/selfservice/viewContent.do?externalId=tn_17534

4
COTOHA

Se vuoi far finta di aver esaurito la memoria, puoi farlo

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

Conosco un paio di modi per causare il dump della JVM di un file di errore chiamando metodi nativi (quelli che sono integrati), ma probabilmente è meglio che tu non sappia come farlo. ;)

3
Peter Lawrey

JNI è una grande fonte di arresti anomali. È inoltre possibile arrestare in modo anomalo utilizzando l'interfaccia JVMTI poiché deve essere scritta anche in C/C++.

3
Jared

Se crei un processo di thread che genera infinitamente più thread (che generano più thread, che ...) alla fine causerai un errore di overflow dello stack nella stessa 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();
    }
}

Questo mi ha dato l'output (dopo 5 minuti, guarda il tuo ariete)

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

Più breve? Utilizzare la classe Robot per attivare CTRL + BREAK. L'ho notato quando stavo cercando di chiudere il mio programma senza chiudere la console (non aveva funzionalità di 'uscita').

1
user6022288

Lo sto facendo ora, ma non sono del tutto sicuro di come ... :-) JVM (e la mia app) a volte scompaiono completamente. Nessun errore generato, niente registrato. Passa dal lavorare al non funzionare affatto all'istante senza preavviso.

0
Brian Knoblauch

Se per "arresto anomalo" intendi un'interruzione improvvisa della JVM, come ad esempio la JVM scriverà nel suo hs_err_pid% p.log, puoi farlo in questo modo.

Impostare arg-Xmx su un valore minuscolo e dire a JVM di forzare un arresto anomalo su outofmemory:

 -Xmx10m -XX:+CrashOnOutOfMemoryError

Per essere chiari, senza il secondo argomento sopra, ciò comporterebbe solo il jvm terminando con un OutOfMemoryError, ma non si "arresterebbe" o interromperebbe bruscamente il jvm.

Questa tecnica si è rivelata utile quando stavo provando a testare JVM -XX: arg ErrorFile, che controlla dove dovrebbe essere scritto un tale registro hs_err_pid. Avevo trovato questo post qui, mentre cercavo il modo di forzare un simile incidente. Quando in seguito ho scoperto che quanto sopra funzionava come il più semplice per le mie necessità, volevo aggiungerlo all'elenco qui.

Infine, FWIW, se qualcuno può testarlo quando ha già un valore -Xms impostato nei tuoi arg (su un valore più grande di quello sopra), ti consigliamo di rimuoverlo o cambiarlo, o non otterrai un crash ma semplicemente un errore di avvio di jvm, che riporta "Dimensione heap iniziale impostata su un valore maggiore della dimensione heap massima". (Non sarebbe ovvio se si esegue JVM come servizio, ad esempio con alcuni server di app. Ancora una volta, mi ha morso, quindi volevo condividerlo.)

0
charlie arehart

Questo conta?

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

Funziona solo per Linux e da Java 9.

Per qualche motivo non capisco, ProcessHandle.current().destroyForcibly(); non uccide la JVM e lancia Java.lang.IllegalStateException Con il messaggio distruzione del processo corrente non consentita.

0
mszmurlo