Question

Je lisais un livre sur les compétences en programmation dans lequel l'auteur demandait à l'enquêté: "Comment écraser une JVM?" Je pensais que vous pourriez le faire en écrivant une boucle infinie qui finirait par utiliser toute la mémoire.

Quelqu'un a une idée?

Était-ce utile?

La solution

L'élément le plus proche d'un seul " answer " System.exit () met fin immédiatement à la machine virtuelle Java sans nettoyage approprié. Mais à part cela, l'épuisement du code natif et des ressources est la réponse la plus probable. Sinon, vous pouvez consulter le gestionnaire de bogues de Sun pour rechercher des bogues dans votre version de la machine virtuelle Java, dont certains permettent des scénarios de crash répétables. Nous avions l'habitude de rencontrer des plantages quasi réguliers lorsque nous approchions de la limite de mémoire de 4 Gb sous les versions 32 bits (nous utilisons généralement la version 64 bits maintenant).

Autres conseils

Je n'appellerais pas lancer une exception OutOfMemoryError ou StackOverflowError comme un crash. Ce ne sont que des exceptions normales. Pour réellement planter une machine virtuelle, il existe 3 façons:

  1. Utilisez JNI et plantez le code natif.
  2. Si aucun gestionnaire de sécurité n'est installé, vous pouvez utiliser la réflexion pour faire planter la machine virtuelle. Ceci est spécifique à la machine virtuelle, mais normalement, une machine virtuelle stocke un ensemble de pointeurs vers des ressources natives dans des champs privés (par exemple, un pointeur sur l'objet thread natif est stocké dans un champ long dans java.lang.Thread ). Modifiez-les simplement par réflexion et la machine virtuelle se bloquera tôt ou tard.
  3. Tous les ordinateurs virtuels ont des bogues, vous devez donc en déclencher un.

Pour la dernière méthode, j'ai un court exemple qui plantera une machine virtuelle Sun Hotspot correctement:

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

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

Ceci entraîne un débordement de pile dans le CPG, vous n'aurez donc pas StackOverflowError mais un véritable crash, y compris un fichier hs_err *.

JNI . En fait, avec JNI, le crash est le mode de fonctionnement par défaut. Vous devez travailler très fort pour ne pas tomber en panne.

Utilisez ceci:

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

Cette classe doit figurer sur le chemin d'accès aux classes de démarrage, car elle utilise un code sécurisé. Exécutez-la comme suit:

  

java -Xbootclasspath / p :. Crash

Je suis venu ici parce que j'ai également rencontré cette question dans le programmeur passionné . par Chad Fowler. Pour ceux qui n'ont pas accès à une copie, la question est formulée comme une sorte de filtre / test pour les candidats se présentant pour un poste nécessitant de "très bons programmeurs Java".

Plus précisément, il demande:

  

Comment écririez-vous un programme, en Java pur, qui ferait planter la machine virtuelle Java?

Je programme en Java depuis plus de 15 ans et j'ai trouvé cette question à la fois déconcertante et injuste. Comme d'autres l'ont souligné, Java, en tant que langage géré, est spécifiquement conçu pour ne pas planter . Bien sûr, il y a toujours des bogues JVM, mais:

  1. Après plus de 15 ans de JRE au niveau de la production, c'est rare.
  2. De tels bogues risquent d'être corrigés dans la prochaine version. Dans ce cas, en tant que programmeur, avez-vous des chances de rencontrer et de rappeler les détails de l'ensemble actuel de JRE show-stoppers?

Comme d'autres l'ont mentionné, certains codes natifs via JNI sont un moyen sûr de planter un JRE. Mais l'auteur a spécifiquement mentionné en Java pur , c'est donc fini.

Une autre option serait d’alimenter les faux octets de JRE; Il est assez facile de vider certaines données binaires dans un fichier .class et de demander au JRE de l'exécuter:

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

Est-ce que ça compte? Je veux dire que la JRE elle-même n'a pas planté; il a correctement détecté le code factice, l'a signalé et est sorti.

Cela nous laisse avec les types de solutions les plus évidents, tels que vider la pile via la récursion, manquer de mémoire vive via les allocations d'objets ou simplement lancer RuntimeException . Mais cela provoque simplement la fermeture de JRE avec une StackOverflowError ou une exception similaire, ce qui, encore une fois n'est pas vraiment un crash .

Alors, que reste-t-il? J'aimerais vraiment savoir ce que l'auteur pensait vraiment comme solution appropriée.

Mise à jour : Chad Fowler, a répondu ici .

PS: c'est un excellent livre. Je l'ai pris pour un soutien moral tout en apprenant Ruby.

Ce code plantera la machine virtuelle Java de manière désagréable

import sun.dc.pr.PathDasher; 

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

La dernière fois que j'ai essayé, cela le ferait:

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

Première partie du fichier journal généré:

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

Une implémentation JVM parfaite ne plantera jamais.

Pour faire planter une machine virtuelle, en dehors de JNI, vous devez rechercher un bogue dans la machine virtuelle elle-même. Une boucle infinie ne consomme que du processeur. L'allocation infinie de mémoire devrait simplement entraîner la perte de OutOfMemoryError dans une JVM bien construite. Cela poserait probablement des problèmes à d’autres threads, mais une bonne machine virtuelle Java ne devrait toujours pas tomber en panne.

Si vous pouvez trouver un bogue dans le code source de la machine virtuelle et provoquer, par exemple, une erreur de segmentation dans l'utilisation de la mémoire par la mise en oeuvre de la machine virtuelle, vous pouvez réellement le bloquer.

Si vous voulez faire planter la machine virtuelle Java - utilisez les méthodes suivantes dans le JDK Sun 1.6_23 ou inférieur:

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

Ceci est dû à un bug dans Sun JDK - également trouvé dans OpenJDK. Ceci est corrigé à partir d'Oracle JDK 1.6_24.

Cela dépend de ce que vous entendez par crash.

Vous pouvez faire une récursion infinie pour le faire manquer d'espace de pile, mais cela plantera "gracieusement". Vous obtiendrez une exception, mais la machine virtuelle elle-même s’occupera de tout.

Vous pouvez également utiliser JNI pour appeler du code natif. Si vous ne le faites pas juste comme il faut, vous pouvez le rendre dur. Déboguer ces accidents est "amusant". (croyez-moi, je devais écrire une grosse DLL C ++ que nous appelons à partir d'un applet Java signé). :)

Le livre machine virtuelle Java de Jon Meyer a un exemple d’une série d’instructions de bytecode qui ont provoqué le vidage de la machine virtuelle Java. Je ne trouve pas mon exemplaire de ce livre. Si quelqu'un en a un, regardez-le et publiez la réponse.

sur winxpsp2 avec wmp10 jre6.0_7

Desktop.open (uriToAviOrMpgFile)

Ceci a pour effet qu'un fil créé génère un point chaud non capturé et se bloque

YMMV

Un matériel cassé peut planter n’importe quel programme. Une fois, une application a planté de manière reproductible sur une machine spécifique alors que tout fonctionnait correctement sur d'autres machines dotées de la même configuration. Il s'avère que cette machine avait une RAM défectueuse.

moyen le plus court possible:)

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

Pas un crash, mais plus proche d'un crash que la réponse acceptée d'utiliser System.exit

Vous pouvez arrêter la machine virtuelle Java en appelant

Runtime.getRuntime (). halt (statut)

Selon la documentation: -

  

"Cette méthode ne provoque pas le démarrage des crochets d'arrêt et n'exécute pas de finaliseurs non invoqués si la finalisation à la sortie a été activée".

Voici une explication détaillée sur les causes du vidage principal de la machine virtuelle Java (par exemple, un crash): http://kb.adobe.com/selfservice/viewContent.do?externalId= tn_17534

Si vous définissez un blocage en tant qu'abandon du processus en raison d'une situation non gérée (c'est-à-dire sans exception ou erreur Java), cette opération ne peut pas être effectuée à partir de Java (sauf si vous êtes autorisé à utiliser la classe sun.misc.Unsafe). . C’est tout l’intérêt du code géré.

Les pannes typiques dans le code natif se produisent en annulant le référencement des pointeurs vers des zones de mémoire erronées (adresse nulle ou mal alignée). Une autre source pourrait être des instructions de machine illégales (opcodes) ou des signaux non gérés provenant d’appels à la bibliothèque ou au noyau. Les deux peuvent être déclenchés si la machine virtuelle ou les bibliothèques système contiennent des bogues.

Par exemple, le code JITed (généré), les méthodes natives ou les appels système (pilote graphique) peuvent poser des problèmes pouvant entraîner de véritables plantages (il était assez courant d’obtenir un blocage lorsque vous utilisiez des fonctions ZIP et que leur mémoire était saturée). Dans ces cas, le gestionnaire d'accidents de la machine virtuelle Java déclenche et exporte l'état. Il pourrait également générer un fichier de base du système d'exploitation (Dr. Watson sous Windows et core dump sous * nix).

Sous Linux / Unix, vous pouvez facilement faire planter une machine virtuelle Java en l'envoyant un signal au processus en cours d'exécution. Remarque: vous ne devez pas utiliser SIGSEGV pour cela, car Hotspot capte ce signal et le relance sous la forme d'une exception NullPointerException dans la plupart des endroits. Il est donc préférable d’envoyer un SIGBUS par exemple.

Si vous voulez faire semblant d'être à court de mémoire, vous pouvez le faire

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

Je connais un moyen de provoquer le vidage d'un fichier d'erreur par la machine virtuelle Java en appelant des méthodes natives (intégrées), mais il est probablement préférable de ne pas savoir comment procéder. ;)

JNI est une source importante de crash. Vous pouvez également bloquer l’interface JVMTI, car elle doit également être écrite en C / C ++.

Si vous créez un processus de thread générant infiniment plus de threads (générant plus de threads, qui ...), vous causerez éventuellement une erreur de débordement de pile dans la machine virtuelle elle-même.

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

Cela m'a donné la sortie (après 5 minutes, surveillez votre bélier)

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

Le plus court? Utilisez la classe Robot pour déclencher CTRL + BREAK. Je l’ai repéré lorsque j’essayais de fermer mon programme sans fermer la console (la fonctionnalité «Exit» n’existait pas).

Je le fais maintenant, mais je ne sais pas trop comment ... :-) Parfois, la JVM (et mon application) disparaissent complètement. Aucune erreur jetée, rien enregistré. Va de ne pas fonctionner du tout instantanément sans avertissement.

Est-ce que cela compte?

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

Cela ne fonctionne que sous Linux et à partir de Java 9.

Pour une raison quelconque, je ne comprends pas, ProcessHandle.current (). destroyForcibly (); ne tue pas la machine virtuelle Java et jette java.lang.IllegalStateException avec le message destruction du processus en cours non autorisé .

Si vous modifiez cette boucle for infinie en appel récursif de la même fonction, vous obtiendrez une exception de débordement de pile:

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

public void causeStackOverflow() {
    causeStackOverflow();
}

Si un "crash" est quelque chose qui interrompt le programme jvm / de la terminaison normale, alors une exception non gérée pourrait le faire.

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
  }

Alors, cela dépend de quel type de CRASH?!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top