5

Un OutOfMemoryError se produit lorsque le tas n'a pas assez de mémoire pour créer de nouveaux objets. Si le tas n'a pas assez de mémoire, où est créé l'objet . J'essaie de comprendre cela, s'il vous plaît conseiller.Où l'objet OutOfMemoryError est-il créé en Java?

+0

excellente question d'entrevue IMO - mais je l'aurais échoué. merci de l'avoir posté – Eugene

Répondre

4

Il est généré de manière native par la JVM, qui n'est pas limitée par -Xmx ou d'autres paramètres. Le tas réservé pour votre programme est épuisé, pas la mémoire disponible pour la JVM.

+0

Merci. Eh bien, c'était l'une des questions d'entrevue qui m'a été posée dans une interview. – manjosh

+0

En fait, [c'est un peu plus compliqué] (https://stackoverflow.com/a/46298757/2711488) ... – Holger

6

Bien sûr, il s'agit d'un comportement dépendant de l'implémentation. HotSpot a une mémoire de tas inaccessible pour les allocations ordinaires, la JVM peut utiliser pour construire un OutOfMemoryError po. Cependant, puisque Java autorise un nombre arbitraire de threads, un nombre arbitraire de threads peut frapper le mur en même temps, donc il n'y a pas de garantie que la mémoire est suffisante pour construire une instance distincte OutOfMemoryError pour chacun d'entre eux. Par conséquent, une instance d'urgence OutOfMemoryError est créée au démarrage de la machine virtuelle Java et persiste tout au long de la session, afin de garantir que l'erreur peut être renvoyée même s'il n'y a plus de mémoire disponible. Puisque l'instance sera partagée pour tous les threads rencontrant l'erreur alors qu'il n'y a plus vraiment de mémoire, vous reconnaîtrez cette condition étrangère par le fait que cette erreur n'aura alors aucune trace de pile.

Le programme suivant

ConcurrentHashMap<OutOfMemoryError,Integer> instances = new ConcurrentHashMap<>(); 

ExecutorService executor = Executors.newCachedThreadPool(); 
executor.invokeAll(Collections.nCopies(1000,() -> { 
      ArrayList<Object> list = new ArrayList<>(); 
      for(;;) try { 
       list.add(new int[10_000_000]); 
      } catch(OutOfMemoryError err) { 
       instances.merge(err, 1, Integer::sum); 
       return err; 
      } 
     })); 
executor.shutdown(); 
System.out.println(instances.size()+" distinct errors created"); 
instances.forEach((err,count) -> { 
    StackTraceElement[] trace = err.getStackTrace(); 
    System.out.println(err.getClass().getName()+"@"+Integer.toHexString(err.hashCode()) 
     +(trace!=null&&trace.length!=0? " has": " has no")+" stacktrace, used "+count+'x'); 
}); 

fonctionnant sous jdk1.8.0_65 avec -Xmx100M et d'attendre une demi-minute m'a donné

5 distinct errors created 
[email protected] has no stacktrace, used 996x 
[email protected] has stacktrace, used 1x 
[email protected] has stacktrace, used 1x 
[email protected] has stacktrace, used 1x 
[email protected] has stacktrace, used 1x 

montrant que la mémoire réservée pourrait servir la construction de quatre cas OutOfMemoryError distincts (y compris le mémoire nécessaire pour enregistrer leurs traces de pile) alors que tous les autres threads devaient revenir à l'instance partagée réservée.

Bien sûr, les nombres peuvent varier entre différents environnements.

+0

très intéressant, je n'avais aucune idée à ce sujet – Eugene