Come si blocca una JVM?


144

Stavo leggendo un libro sulle abilità 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?



stackoverflow.com/questions/30072883/… "Se utilizzo JDK1.8_40 o più recente (Oracle o OpenJDK fanno lo stesso), il codice seguente, insieme a un ridimensionamento della finestra di dialogo, bloccherà l'applicazione (provato Windows 7, x64, JDK a 64 bit)" - Il codice ha solo 40 righe e provoca un arresto anomalo corretto della JVM.
presidente di Dreamspace il

Risposte:


6

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).


71
senza una corretta pulizia? sei sicuro? La documentazione dice "Termina la macchina virtuale Java attualmente in esecuzione avviando la sua sequenza di arresto ... tutti gli hook di arresto registrati, se presenti, vengono avviati ... vengono eseguiti tutti i finalizzatori non invocati" - non è la pulizia corretta?
user85421

51
Questo non sta causando l'arresto anomalo della JVM, ma intenzionalmente ed esplicitamente avvia un arresto ordinato dell'esecuzione.
BenM,

9
Più vicino all'arresto anomalo di jvm è Runtime.getRuntime (). Halt (stato). Secondo i documenti "questo metodo non provoca l'avvio di hook di arresto e non esegue finalizzatori non invocati se la finalizzazione all'uscita è stata abilitata". Ancora non un arresto anomalo, ma più vicino di System.exit.
Henry,

48
Questa è davvero una cattiva risposta.
Antonio,

174

Non chiamerei lanciare un OutOfMemoryError o StackOverflowError un arresto anomalo. Queste sono solo normali eccezioni. Per arrestare veramente una 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 è specifico della VM, ma normalmente una VM memorizza un sacco di puntatori a risorse native in campi privati ​​(ad es. Un puntatore all'oggetto thread nativo è memorizzato in un lungo campo in java.lang.Thread ). Basta cambiarli tramite reflection e la VM si bloccherà 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 si bloccherà in modo discreto una VM Sun Hotspot:

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 *.


9
Wow! Ciò provoca l'arresto anomalo di Sun Java 5, Sun Java 6 e OpenJDK 6 (su Ubuntu 9.04) senza file hs_err * ma solo "Errore di segmentazione!" ...
Joachim Sauer,

1
System.exit () è un modo molto più semplice per bloccare un JVM (a meno che non sia installato un gestore della sicurezza)
instantsetsuna

4
Non so quando è stato risolto, ma appena testato in 1.7.0_09 e va bene. Ho appena ottenuto l'atteso: eccezione nel thread "main" java.lang.OutOfMemoryError: spazio heap Java su CrashJVM.main (CrashJVM.java:7)
Chad NB,

2
Ho provato il codice sopra su Intel Core i7 2.4 GHz / 8 GB RAM / JDK1.7 64 bit ma JVM è ancora attivo dopo 20 minuti. (Divertente: la ventola del mio laptop era più forte di un jet da combattimento nel cielo). Questo problema è stato risolto in JDK 1.7+?
realPK

3
In JDK 1.8_u71 questo provoca unjava.lang.OutOfMemoryError: GC overhead limit exceeded
Clashsoft il

124

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


4
Forse i progettisti di JNI avevano sentito parlare del software solo per crash , ma non avevano ancora compreso l'idea.
Tom Anderson,

56

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


14
Invece di usare -Xbootclasspath puoi anche solo fare questo: ha funzionato alla Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null );grande per me.
invadente

Unsafeè, per definizione, "non sicuro". Questo è un po 'un trucco.
Hot Licks

1
Confermato il lavoro usando il getDeclaredFieldtrucco in JDK 8u131 su Linux x64, inclusa la produzione di hs_err_pid*.logda a SIGSEGV.
Jesse Glick,

L'uso Unsafenon è un imbroglione. OP non sta cercando una soluzione "pulita" a un problema di programmazione. Ha bisogno che la jvm si schianti nel modo più brutto possibile. Fare cose native cattive è ciò che può farlo accadere ed è esattamente ciò che Unsafefa.
jvdneste,

34

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 specie di filtro / test per i candidati che intervistano per una posizione che richiede "programmatori Java davvero bravi".

In particolare, chiede:

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

Ho programmato in Java per oltre 15 anni e ho trovato questa domanda perplessa e ingiusta. Come altri hanno sottolineato, Java, come linguaggio gestito, è specificamente progettato per non arrestarsi in modo anomalo . 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 nello specifico Java puro , quindi è tutto fuori.

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 sì che JRE esca con StackOverflowErrorun'eccezione simile o simile, che, di nuovo, non è davvero 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.


1
Tali domande di intervista servono come tornasole per gli sviluppatori Java che sono stati in giro abbastanza a lungo da 1) hanno assistito a (molti) crash JVM e 2) hanno tratto alcune conclusioni o, meglio ancora, come (autoproclamato) gli esperti Java hanno provato a capire ragioni sottostanti per un incidente. Chad Fowler afferma anche nel suo libro che i programmatori Java autoproclamati "non sono nemmeno riusciti a trovare la risposta sbagliata", cioè non hanno provato a pensare a quando un'intera classe di potenziali problemi. La linea di fondo: questa domanda è segway a "Come prevenire gli arresti anomali di JVM?" che è chiaramente ancora meglio sapere.
Shonzilla,

1
Vorrei cercare persone che rispondessero (come la maggior parte qui) "overflow dello stack", system.exit () o altri arresti "normali" in quanto non capiscono veramente la JVM o la parola "Crash". Riconoscere (come hai fatto tu) che questo è molto anormale è un buon modo per identificare un programmatore più avanzato. Sono d'accordo con la tua prima affermazione, troverei una domanda eccellente e assolutamente giusta da porre o da fare: quelli senza risposte concrete sono sempre i migliori.
Bill K,

20

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

1
Errore di compilazione durante l'utilizzo di JDK 1.7 con questo codice: Limitazione dell'accesso: il tipo PathDasher non è accessibile a causa della restrizione sulla libreria richiesta C: \ Programmi \ Java \ jdk1.7.0_51 \ jre \ lib \ rt.jar
realPK

7
Questo genera un InternalErrorin JDK 1.8. JVM non fallisce più.
Sotirios Delimanolis,

18

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

Sono un po 'divertito dal downvote, dato che questa è una delle uniche due risposte che mostrano come farlo puramente con il codice Java e include il codice completo.
Hot Licks

Concordo sul fatto che un downvote sia ingiustificato: si tratta di un vero incidente, ma come risponderesti alla domanda dell'intervista. A meno che non avessi precedentemente studiato e memorizzato questo, non potresti dargli una risposta nell'intervista e se potessi considererei comunque una risposta da neutrale a scarsa - non mostra come affronteresti il ​​problema. Mi aspetto che quello che hai fatto sia stato Google per exploit di bug jvm e implementarne uno che sia un'ottima risposta.
Bill K,

@BillK - No, quanto sopra è interamente opera mia, anche se me ne sono inventato diversi anni fa, sperimentando varie cose. In un'intervista probabilmente direi "L'ho fatto, usando try / catch e ricorsione, ma non riesco a scuotere il codice esatto proprio ora."
Hot Licks

1
Quali sono i dettagli (versione JDK, eventuali argomenti VM)? Non sono sicuro di quale sia la versione "11.2-b0". Sto eseguendo questo, ma consuma solo molta CPU.
Stefan Reich,

@Hot Licks: qual è il concetto nell'esempio del crash di JVM? Perché JVM si blocca sul codice. Tutti i thread hanno thread stack separati ...
VJS

15

Una perfetta implementazione JVM non si arresterà mai.

Per interrompere un JVM, oltre a JNI, è necessario trovare un bug nella VM stessa. Un ciclo infinito consuma solo CPU. L'allocazione infinita della memoria dovrebbe causare OutOfMemoryError in una JVM ben costruita. Ciò 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.


14

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 un bug in Sun JDK, presente anche in OpenJDK. Questo è stato risolto da Oracle JDK 1.6_24 in poi.


10

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 una grande DLL C ++ che chiamiamo da un'applet java firmata). :)


6

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, cercalo e pubblica la risposta.


5

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

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

modo più breve possibile :)

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

Non va in crash. Dà errore di compilazione Exception in thread "main" java.lang.StackOverflowError at Test.main. Sto usando jdk1.8.0_65
Quazi Irfan il

5

Non un crash, ma più vicino a un crash della risposta accettata dell'utilizzo System.exit

È possibile interrompere la 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".



4

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. ;)


4

Se si definisce un arresto anomalo come interruzione di un processo a causa di una situazione non gestita (ovvero nessuna eccezione o errore Java), ciò non può essere fatto all'interno di Java (a meno che non si disponga dell'autorizzazione per utilizzare 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 quei 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 usarlo SIGSEGVper questo, poiché Hotspot cattura questo segnale e lo re-lancia come NullPointerException nella maggior parte dei luoghi. Quindi è meglio inviare un SIGBUSesempio.


3

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


2

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

1

Se per "arresto anomalo" intendi un'interruzione improvvisa della JVM, 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 la terminazione di jvm con un OutOfMemoryError, ma non si "arresterebbe" o interromperebbe bruscamente il jvm.

Questa tecnica si è rivelata utile quando stavo cercando di 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 dell'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

Se cambi l'infinito per il ciclo in una chiamata ricorsiva alla stessa funzione, otterrai un'eccezione di overflow dello stack:

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

public void causeStackOverflow() {
    causeStackOverflow();
}

0

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.


Inizia a controllare il tuo hardware, specialmente la tua memoria!
Thorbjørn Ravn Andersen,

Sfortunatamente, è su più macchine che altrimenti funzionano bene. È solo questa particolare app che lo fa (e non richiede molta memoria o processore).
Brian Knoblauch,

0

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').


Vecchia domanda: si spera che qualcuno trarrà beneficio dalla tua risposta in futuro.
dbmitch,

0

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.IllegalStateExceptioncon il messaggio di distruzione del processo corrente non consentito .


0

Incappare in questo problema quando si tenta di replicare l'arresto anomalo di JVM.

Jni funziona, ma deve essere ottimizzato per piattaforme diverse. Alla fine, utilizzo questa combinazione per bloccare JVM

  1. Avviare l'applicazione con queste opzioni JVM -XX:+CrashOnOutOfMemoryError
  2. Utilizzare a long[] l = new long[Integer.MAX_VALUE];per attivare OOM

Quindi JVM si arresta in modo anomalo e genera il registro degli arresti anomali.


-2

Se un 'arresto anomalo' è qualcosa che interrompe jvm / programma dalla normale terminazione, un'eccezione non gestita potrebbe farlo.

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
  }

Quindi, dipende da quale tipo di CRASH ?!


3
Generare un'eccezione non è un arresto anomalo.
Quazi Irfan,

Eccezioni di runtime non gestite sono incidenti, però, che ArithmeticExceptionè
a metà
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.