Domanda

Stavo leggendo un libro sulle abilità di programmazione in cui l'autore chiede all'intervistato: "Come fai a schiantarsi un JVM?" Ho pensato che potessi farlo scrivendo un infinito per loop che alla fine avrebbe usato tutto il ricordo.

Qualcuno ha qualche idea?

È stato utile?

Soluzione

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

Altri suggerimenti

Non definirei un arresto anomalo il lancio di un OutOfMemoryError o StackOverflowError.Queste sono solo normali eccezioni.Per mandare in crash davvero una VM ci sono 3 modi:

  1. Usa JNI e si blocca nel codice nativo.
  2. Se non è installato alcun gestore della sicurezza, è possibile utilizzare la riflessione per arrestare in modo anomalo la VM.Questo è specifico della VM, ma normalmente una VM memorizza una serie di puntatori a risorse native in campi privati ​​(ad es.un puntatore all'oggetto thread nativo viene memorizzato in un campo lungo in java.lang.Thread).Basta cambiarli tramite riflessione e prima o poi la VM si bloccherà.
  3. Tutte le VM hanno bug, quindi devi solo attivarne uno.

Per l'ultimo metodo ho un breve esempio, che manderà in crash una VM Sun Hotspot in modo silenzioso:

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

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

Ciò porta a un overflow dello stack nel GC, quindi non si otterrà StackOverflowError ma un vero e proprio arresto anomalo che include un file hs_err*.

JNI.In effetti, con JNI, l'arresto anomalo è la modalità operativa predefinita.Devi lavorare molto duramente per evitare che si schianti.

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 nel classpath di avvio perché utilizza codice attendibile, quindi esegui in questo modo:

java -Xbootclasspath/p:.Incidente

Sono venuto qui perché anch'io mi sono imbattuto in questa domanda Il programmatore appassionato, di Chad Fowler.Per coloro che non hanno accesso a una copia, la domanda è strutturata come una sorta di filtro/test per i candidati che fanno un colloquio per una posizione che richiede "programmatori Java davvero bravi".

Nello specifico chiede:

Come scriveresti un programma, in puro Java, che causerebbe il crash della Java Virtual Machine?

Programmavo in Java da oltre 15 anni e ho trovato questa domanda sconcertante e ingiusta.Come altri hanno sottolineato, Java, come linguaggio gestito, è progettato specificamente per non schiantarsi.Ovviamente ci sono sempre bug 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 quanto è probabile che tu, come programmatore, ti imbatti e ricordi i dettagli dell'attuale serie di problemi JRE?

Come altri hanno già detto, parte del codice nativo tramite JNI è un modo sicuro per mandare in crash un JRE.Ma l'autore ha espressamente menzionato in puro Java, quindi è fuori.

Un'altra opzione sarebbe quella di alimentare i codici byte fasulli di JRE;è abbastanza semplice scaricare alcuni dati binari spazzatura 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

Conta?Voglio dire, il JRE stesso non si è bloccato;ha rilevato correttamente il codice fasullo, lo ha segnalato ed è uscito.

Questo ci lascia con i tipi più ovvi di soluzioni come far saltare lo stack tramite la ricorsione, esaurire la memoria heap tramite allocazioni di oggetti o semplicemente lanciare RuntimeException.Ma questo fa semplicemente uscire JRE con a StackOverflowError o eccezione simile, che, ancora una volta non è davvero un incidente.

Quindi cosa resta?Mi piacerebbe davvero sentire cosa aveva veramente in mente l'autore come soluzione adeguata.

Aggiornamento:Chad Fowler ha risposto qui.

PS:per il resto è un libro fantastico.L'ho preso per supporto morale mentre imparavo Ruby.

Questo codice manderà in crash la JVM in modi sgradevoli

import sun.dc.pr.PathDasher; 

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

L'ultima volta che ho provato questo avrebbe funzionato:

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

Una perfetta implementazione JVM non andrà mai in crash.

Per mandare in crash una JVM, a parte JNI, è necessario trovare un bug nella VM stessa.Un ciclo infinito consuma solo CPU.L'allocazione infinita della memoria dovrebbe causare solo OutOfMemoryError in una JVM ben costruita.Ciò probabilmente causerebbe problemi ad altri thread, ma una buona JVM non dovrebbe comunque bloccarsi.

Se riesci a trovare un bug nel codice sorgente della VM e, ad esempio, causare un errore di segmentazione nell'utilizzo della memoria dell'implementazione della VM, puoi effettivamente bloccarla.

Se vuoi mandare in crash JVM, usa quanto segue in Sun JDK 1.6_23 o versioni precedenti:

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

Ciò è dovuto a insetto in Sun JDK - trovato anche in OpenJDK.Questo problema è stato risolto da Oracle JDK 1.6_24 in poi.

Dipende cosa intendi per incidente.

Puoi eseguire una ricorsione infinita per esaurire lo spazio nello stack, ma ciò si bloccherà "con grazia".Riceverai un'eccezione, ma la JVM stessa gestirà tutto.

Puoi anche utilizzare 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).:)

Il libro macchina virtuale Java di Jon Meyer contiene un esempio di una serie di istruzioni bytecode che hanno causato il core 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.

su winxpsp2 con wmp10 jre6.0_7

Desktop.open(uriToAviOrMpgFile)

Ciò fa sì che un thread generato lanci un Throwable non rilevato e provochi l'arresto anomalo dell'hotspot

YMMV

L'hardware rotto può mandare in crash qualsiasi programma.Una volta ho avuto un arresto anomalo riproducibile dell'app su un computer specifico mentre funzionava correttamente su altri computer con la stessa identica configurazione.Si scopre che la macchina aveva una RAM difettosa.

la strada più breve possibile :)

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

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

Puoi fermare la JVM chiamando

Runtime.getRuntime().halt( status )

Secondo i documenti: -

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

ecco una spiegazione dettagliata su cosa causa il core dump di JVM (ad es.incidente):http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534

Se definisci un arresto anomalo come un'interruzione del processo a causa di una situazione non gestita (ad es.nessuna eccezione o errore Java), l'operazione non può essere eseguita da Java (a meno che non si disponga dell'autorizzazione per utilizzare la classe sun.misc.Unsafe).Questo è il punto centrale del codice gestito.

I tipici arresti anomali del codice nativo si verificano quando i puntatori vengono dereferenziati ad aree di memoria errate (indirizzo nullo o disallineato).Un'altra fonte potrebbe essere istruzioni macchina illegali (codici operativi) o segnali non gestiti da chiamate alla libreria o al kernel.Entrambi possono essere attivati ​​se la JVM o le librerie di sistema presentano bug.

Ad esempio, il codice JIT (generato), i metodi nativi o le chiamate di sistema (driver grafico) possono avere problemi che portano a veri e propri arresti anomali (era abbastanza comune avere un arresto anomalo quando si utilizzavano le funzioni ZIP e si esauriva la memoria).In questi casi, il gestore degli arresti anomali della JVM si attiva 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 puoi facilmente causare un arresto anomalo della JVM inviando un segnale al processo in esecuzione.Nota:non dovresti usare SIGSEGV per questo, poiché Hotspot rileva questo segnale e lo rilancia come NullPointerException nella maggior parte dei punti.Quindi è meglio inviare un SIGBUS Per esempio.

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 far sì che la JVM scarichi un file di errore chiamando metodi nativi (quelli integrati), ma probabilmente è meglio che tu non sappia come farlo.;)

JNI è una grande fonte di arresti anomali.Puoi anche bloccarti utilizzando l'interfaccia JVMTI poiché anche questa deve essere scritta in C/C++.

Se crei un processo di thread che genera all'infinito più thread (che generano più thread, che...) alla fine causerai un errore di overflow dello stack nella JVM stessa.

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

Il più breve?Utilizza la classe Robot per attivare CTRL+INTERR.L'ho notato mentre stavo cercando di chiudere il mio programma senza chiudere la console (non aveva la funzionalità di "uscita").

Lo sto facendo adesso, ma non sono del tutto sicuro di come...:-) JVM (e la mia app) a volte scompaiono completamente.Nessun errore generato, nulla registrato.Passa dal funzionamento al mancato funzionamento istantaneamente senza preavviso.

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.

Se modifichi il ciclo for infinito 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();
}

Se un "Crash" è qualcosa che interrompe la normale terminazione del jvm/programma, allora 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 che tipo di CRASH ?!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top