Vra

Ek was die lees van 'n boek oor programmeringsvaardighede waarin die skrywer vra die onderhoud gevoer word, "Hoe kan jy 'n JVM crash?" Ek het gedink dat jy so kan doen deur die skryf van 'n oneindige vir-lus wat uiteindelik sou gebruik om al die geheue.

Enigiemand het 'n idee?

Was dit nuttig?

Oplossing

Die naaste ding aan 'n enkele "antwoord" is System.exit() wat die JVM onmiddellik beëindig sonder behoorlike opruim. Maar afgesien van dat, inheemse kode en uitputting van hulpbronne is die mees waarskynlike antwoorde. Alternatiewelik kan jy gaan kyk op Sun se forum vir foute in jou weergawe van die JVM, waarvan sommige voorsiening te maak vir herhaalbare crash scenario's. Ons gebruik word om semi-gereelde ongelukke kry wanneer nader die 4 Gb geheue limiet onder die 32-bis-weergawes (ons oor die algemeen gebruik nou 64-bit).

Ander wenke

Ek sou nie noem gooi 'n OutOfMemoryError of StackOverflowError n ongeluk. Dit is net 'n normale uitsonderings. Om werklik te crash 'n VM is daar 3 maniere:

  1. Gebruik JNI en crash in die inheemse kode.
  2. Indien geen sekuriteit bestuurder geïnstalleer kan jy weerspieëling gebruik om die VM crash. Dit is VM spesifieke, maar gewoonlik 'n VM winkels 'n klomp van die verwysings na inheemse hulpbronne in private velde (bv 'n verwysing na die moedertaal draad voorwerp gestoor in 'n lang veld in java.lang.Thread ). verander hulle net via besinning en die VM sal vroeër of later crash.
  3. Alle VMS het foute, so jy moet net een aktiveer.

Vir die laaste metode Ek het 'n kort voorbeeld, wat 'n Sun Hotspot VM stil mooi sal crash:

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

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

Dit lei tot 'n stapel oorloop in die GC sodat jy geen StackOverflowError maar 'n werklike crash insluitend 'n hs_err * lêer sal kry.

JNI . Trouens, met JNI, gekraak is die standaard modus operandi. Jy het ekstra hard te werk om dit te kry om nie te crash.

Gebruik hierdie:

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

Hierdie klas moet wees op die boot classpath want dit is die gebruik van betroubare kode, so hardloop soos hierdie:

  

java -Xbootclasspath / p :. Ongeluk

Ek het hierheen gekom omdat ek ook gehardloop in hierdie vraag in Die Passionate Programmer , deur Chad Fowler. Vir diegene wat nie toegang tot 'n afskrif wil hê, is die vraag opgestel as 'n soort van filter / toets vir kandidate onderhoude vir 'n posisie wat "regtig 'n goeie Java programmeerders."

Spesifiek, vra hy:

  

Hoe sou jy 'n program skryf, in suiwer Java, wat sou veroorsaak dat die Java Virtual Machine te crash?

Ek het in Java geprogrammeer vir meer as 15 jaar, en ek het gevind dat hierdie vraag beide verwarrend en onregverdig te wees. Soos ander het daarop gewys, Java, as 'n bestuurde taal, is spesifiek ontwerp om nie te crash . Natuurlik is daar altyd JVM foute, maar:

  1. Na 15 + jaar van produksie-vlak JREs, dit is skaars.
  2. Enige sodanige foute is geneig om te word gelap in die volgende release, so hoe waarskynlik is jy as 'n programmeerder te loop in en herinner aan die besonderhede van die huidige stel JRE show-stoppers?

As ander genoem het, 'n paar inheemse kode via JNI is 'n seker manier om 'n JRE crash. Maar die skrywer spesifiek genoem in suiwer Java , so dit is uit.

Nog 'n opsie sou wees om die JRE valse byte kodes voed; dit is maklik genoeg om 'n paar vullis binêre data te stort 'n CLASS lêer, en vra die JRE om dit uit te voer:

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

Maak dit tel? Ek bedoel die JRE self het nie neergestort; dit behoorlik bespeur die valse kode, berig dit, en opgewonde.

Dit laat ons met die mees voor die hand liggend soorte oplossings soos waai die stapel via rekursie, besig om van hoop geheue via voorwerp toekennings, of eenvoudig gooi RuntimeException. Maar dit net veroorsaak dat die JRE om af te sluit met 'n StackOverflowError of soortgelyke uitsondering, wat, weer is nie regtig 'n ongeluk .

So wat oorbly? Ek wil regtig graag wou hoor wat die skrywer eintlik in gedagte gehad het as 'n behoorlike oplossing.

Update :. Chad Fowler hier gereageer

PS: dit is 'n andersins goeie boek. Ek het dit opgetel vir morele ondersteuning, terwyl die leer Ruby.

Hierdie kode sal die JVM in nare maniere crash

import sun.dc.pr.PathDasher; 

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

Die laaste keer wat ek probeer dit sou doen:

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

Die eerste deel van die gegenereerde log lêer:

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

'n perfekte implementering JVM sal nooit crash.

Om 'n JVM crash, opsy, weg van JNI, moet jy 'n fout in die VM self vind. 'N oneindige lus verorber net CPU. Oneindig toekenning geheue moet net veroorsaak OutOfMemoryError se in 'n goed gebou JVM. Dit sou waarskynlik probleme vir ander drade veroorsaak, maar 'n goeie JVM moet nog nie crash.

As jy 'n fout in die bronkode van die VM kan vind, en byvoorbeeld veroorsaak dat 'n segmentering skuld in die geheue gebruik van die implementering van die VM, dan kan jy eintlik crash nie.

As jy wil om te crash JVM - gebruik die volgende in Sun JDK 1.6_23 of hieronder:

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

Dit is te danke aan 'n fout in Sun JDK - ook gevind in OpenJDK. Dit is vasgestel van Oracle JDK 1.6_24 af.

Dit hang af van wat jy bedoel met crash.

Jy kan 'n oneindige rekursie doen om dit te laat hardloop uit stapel ruimte, maar wat sal "grasieus" crash. Jy sal 'n uitsondering te kry, maar die JVM self sal hanteer alles.

Jy kan ook JNI gebruik om inheemse kode bel. As jy dit nie net reg dan doen wat jy kan maak dit crash hard. Debugging dié ongelukke is "pret" (glo my, ek het 'n groot C ++ DLL dat ons 'n beroep van 'n getekende java applet skryf). :)

Die boek Java Virtual Machine deur Jon Meyer het 'n voorbeeld van 'n reeks van bytecode instruksies wat die JVM te stort veroorsaak. Ek kan my kopie van hierdie boek vind nie. As iemand daar buite 'n mens moet asseblief kyk dit op en plaas die antwoord.

op winxpsp2 w / wmp10 jre6.0_7

Desktop.open (uriToAviOrMpgFile)

Dit veroorsaak 'n produseer draad om 'n uncaught Gooibaar gooi en ineenstortings hotspot

YMMV

Broken hardeware kan enige program crash. Een keer het ek 'n app crash reproducably op 'n spesifieke masjien terwyl hy loop fyn op ander masjiene met presies dieselfde setup. Blyk dat die masjien het foutiewe RAM.

kortste moontlike manier:)

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

Nie 'n ongeluk, maar nader aan 'n ongeluk as die aanvaarde antwoord van die gebruik van System.exit

Jy kan die JVM te stop deur te bel

Runtime.getRuntime().halt( status )

Volgens die dokumente: -

  

"hierdie metode veroorsaak nie afsluit hakies te begin en nie uninvoked finalizers hardloop as finalisering-op-afrit is geaktiveer".

hier is 'n gedetailleerde verduideliking van wat veroorsaak dat JVM te stort (maw crash): http://kb.adobe.com/selfservice/viewContent.do?externalId= tn_17534

As jy 'n ongeluk te definieer as 'n proses te staak as gevolg van 'n verwerkte situasie (dws geen Java uitsondering of fout), dan is dit kan nie gedoen word vanuit Java (tensy jy toestemming om die sun.misc.Unsafe klas gebruik het) . Dit die hele punt van beheer kode.

Tipiese ongelukke in inheemse kode gebeur deur-de verwysing verwysings na verkeerde geheue gebiede (nul adres of missaligned). Nog 'n bron kan wees onwettige instruksies masjien (opcodes) of verwerkte seine van biblioteek of kern oproepe. Beide kan veroorsaak word as die JVM of die stelsel biblioteke het foute.

Byvoorbeeld JITed (gegenereer) kode, inheemse metodes of stelsel oproepe (grafiese bestuurder) kan probleme wat lei tot werklike ongelukke het (dit was redelik algemeen om 'n ongeluk te kry wanneer jy gebruik zip funksies en hulle hardloop uit geheue). In sulke gevalle die Omval Handteerder van die JVM skop in en dumps die staat. Dit kan ook genereer 'n OS kern lêer (Dr. Watson op Windows en stort op * nix).

Op Linux / Unix jy kan easyly maak 'n JVM ongeluk deur dit 'n sein aan die gang proses. Let wel: moet jy nie gebruik SIGSEGV vir hierdie, want Hotspot vang hierdie sein en re-gooi dit as 'n NullPointerException in die meeste plekke. Daarom is dit beter om 'n SIGBUS stuur byvoorbeeld.

As jy wil voorgee jy uit die geheue wat jy kan doen is loop

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

Ek ken 'n paar van die pad na die JVM veroorsaak stort 'n fout lêer deur te bel moedertaal metodes (kinders wat gebou is op), maar sy waarskynlik die beste wat jy nie weet hoe om dit te doen. ;)

JNI is 'n groot bron van ongelukke. Jy kan ook crash met behulp van die JVMTI koppelvlak sedert wat aangespreek moet word geskryf in C / C ++ sowel.

As jy skep 'n draad proses wat oneindig toegevoeg meer drade wat jy uiteindelik 'n stapel oorloop fout sal veroorsaak in die JVM self.

(wat meer drade, wat ... kuit)
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();
    }
}

Dit het my die uitset (na 5 minute, kyk hoe jou 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:
# 

Kortste? Gebruik robot klas te aktiveer ctrl + breek. Ek raakgesien wanneer ek probeer om my program sluit sonder die sluiting van konsole (Dit het geen "afrit" funksie).

Ek doen dit nou, maar nie heeltemal seker hoe ... :-) JVM (en my app) soms net heeltemal verdwyn. Geen foute gegooi, niks geteken nie. Gaan uit werk om nie loop glad onmiddellik met geen waarskuwing.

Is dit tel?

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

Dit werk net vir Linux en uit Java 9.

Vir een of ander rede het ek dit nie kry nie, ProcessHandle.current().destroyForcibly(); nie die dood van die JVM en gooi java.lang.IllegalStateException met die boodskap vernietig van huidige proses nie toegelaat .

As jy dit oneindige lus verander na 'n rekursiewe oproep om dieselfde funksie, dan sal jy 'n stapel oorloop uitsondering kry:

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

public void causeStackOverflow() {
    causeStackOverflow();
}

As 'n "crash" is iets wat die jvm / program onderbreek uit normale beëindiging, dan 'n Un-behandel uitsondering kan dit doen.

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
  }

So, dit hang af van watter tipe van CRASH?!

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top