web-dev-qa-db-fra.com

Est-il possible de rattraper une exception de mémoire en java?

Je suis en train de développer un programme qui nécessiterait une énorme quantité de mémoire, et je veux intercepter une exception de mémoire insuffisante. J'avais entendu dire que ce n'était pas possible à faire, mais curieux de savoir s'il y a un développement à cette fin.

51
jy.

Ce n'est pas une exception; c'est une erreur: Java.lang.OutOfMemoryError

Vous pouvez l'attraper en descendant de Throwable:

try {
    // create lots of objects here and stash them somewhere
} catch (OutOfMemoryError E) {
    // release some (all) of the above objects
}

Cependant, à moins que vous ne fassiez des choses plutôt spécifiques (en allouant des tonnes de choses dans une section de code spécifique, par exemple), vous ne pourrez probablement pas l'attraper car vous ne saurez pas d'où il va être jeté.

83
ChssPly76

C'est possible:

try {
   // tragic logic created OOME, but we can blame it on lack of memory
} catch(OutOfMemoryError e) {
   // but what the hell will you do here :)
} finally {
   // get ready to be fired by your boss
}
53
Suraj Chandran

Vous pouvez intercepter et tenter de récupérer des exceptions OutOfMemoryError (OOM), BUT IT IS PROBABLY A BAD IDEA ... surtout si votre objectif est que l'application " continue".

Il ya un certain nombre de raisons à cela:

  1. Comme d'autres l'ont souligné, il existe de meilleures façons de gérer les ressources mémoire que de libérer explicitement des choses; c'est-à-dire en utilisant SoftReference et WeakReference pour les objets qui pourraient être libérés si la mémoire est insuffisante.

  2. Si vous attendez de manquer de mémoire avant de libérer des éléments, votre application passera probablement plus de temps à exécuter le garbage collector. En fonction de votre version de la JVM et de vos paramètres de réglage du GC, la JVM peut finir par exécuter le GC de plus en plus fréquemment à l'approche du point auquel un MOO sera lancé. Le ralentissement (en termes d'application faisant un travail utile) peut être important. Vous voulez probablement éviter cela.

  3. Si la cause première de votre problème est une fuite de mémoire, il est probable que la capture et la récupération à partir du MOO ne récupéreront pas la mémoire perdue. Votre application continuera un peu, puis MOO encore et encore et encore à des intervalles toujours réduits.

Donc, mon conseil n'est PAS d'essayer de continuer à partir d'un MOO ... sauf si vous savez :

  • où et pourquoi le MOO s'est produit,
  • qu'il n'y aura pas eu de "dommages collatéraux", et
  • que votre récupération libérera suffisamment de mémoire pour continuer.
25
Stephen C

il suffit de jeter cela là-bas pour tous ceux qui se demandent pourquoi quelqu'un pourrait manquer de mémoire: je travaille sur un projet qui manque souvent de mémoire et j'ai dû mettre en œuvre une solution pour cela.

le projet est un composant d'une application d'investigation et d'investigation. après avoir collecté des données sur le terrain (en utilisant une empreinte mémoire très faible, btw), les données sont ouvertes dans notre application d'enquête. l'une des fonctionnalités consiste à effectuer une traversée CFG de toute image binaire arbitraire qui a été capturée sur le terrain (applications à partir de la mémoire physique). ces traversées peuvent prendre du temps, mais produisent des représentations visuelles très utiles du binaire qui a été traversé.

pour accélérer le processus de traversée, nous essayons de garder autant de données dans la mémoire physique que possible, mais les structures de données grandissent au fur et à mesure que le binaire se développe et nous ne pouvons pas tout garder en mémoire (le but est d'utiliser un Java tas inférieur à 256m). Alors, que dois-je faire?

j'ai créé des versions de LinkedLists, Hashtables, etc. sur disque, ce sont des remplacements directs pour leurs homologues et implémentent toutes les mêmes interfaces afin qu'elles soient identiques du monde extérieur.

la différence? ces structures de remplacement coopèrent entre elles, éliminant les erreurs de mémoire et demandant que les éléments les moins récemment utilisés de la collection la moins récemment utilisée soient libérés de la mémoire. la libération de l'élément le vide sur le disque dans un fichier temporaire (dans le répertoire temporaire fourni par le système) et marque les objets d'espace réservé comme "paginés" dans la collection appropriée.

il y a BEAUCOUP de raisons pour lesquelles vous pourriez manquer de mémoire dans une application Java - la racine de la plupart de ces raisons est l'une ou les deux: 1. L'application s'exécute sur une machine contrainte par les ressources (ou tente de limiter l'utilisation des ressources en limitant la taille du segment de mémoire) 2. L'application nécessite simplement de grandes quantités de mémoire (l'édition d'image a été suggérée, mais qu'en est-il de l'audio et de la vidéo? Qu'en est-il des compilateurs comme dans mon cas? Et des collecteurs de données à long terme sans stockage volatile?)

-bit

14
bitflung

Il est possible d'attraper un OutOfMemoryError (c'est un Error, pas un Exception), mais vous devez être conscient qu'il n'y a aucun moyen d'obtenir un comportement défini.
Vous pouvez même obtenir une autre OutOfMemoryError en essayant de l'attraper.

La meilleure façon est donc de créer/utiliser des caches sensibles à la mémoire. Il existe des frameworks (exemple: JCS ), mais vous pouvez facilement créer le vôtre en utilisant SoftReference . Il y a un petit article sur la façon de l'utiliser ici . Suivez les liens dans l'article pour obtenir plus d'informations.

8
Hardcoded

Il y a probablement au moins un bon moment pour intercepter une OutOfMemoryError, lorsque vous allouez spécifiquement quelque chose qui pourrait être beaucoup trop gros:

public static int[] decode(InputStream in, int len) throws IOException {
  int result[];
  try {
    result = new int[len];
  } catch (OutOfMemoryError e) {
    throw new IOException("Result too long to read into memory: " + len);
  } catch (NegativeArraySizeException e) {
    throw new IOException("Cannot read negative length: " + len);
  }
  ...
}
5
Adam Goode

C'est possible, mais si vous manquez de tas, ce n'est pas très utile. S'il existe des ressources qui peuvent être libérées, vous feriez mieux d'utiliser SoftReference ou WeakReference pour ces ressources et leur nettoyage sera automatique.

Je l'ai trouvé utile si vous manquez de mémoire directe avant que cela ne déclenche pas automatiquement un GC pour une raison quelconque. J'ai donc eu des raisons de forcer un GC si je n'arrive pas à allouer un tampon direct.

3
Peter Lawrey

Il est possible d'attraper Any exception. Ecrivez

try{
   // code which you think might throw exception
}catch(Java.lang.Throwable t){
   // you got the exception. Now what??
}

Idéalement, vous n'êtes pas censé attraper Java.lang.Error exceptions. Ne pas intercepter ces exceptions et laisser l'application se terminer peut être la meilleure solution lorsqu'elles se produisent. Si vous pensez que vous pouvez très bien gérer de telles erreurs, alors allez-y.

2
jai

Bien sûr, la capture de OutOfMemoryError est autorisée. Assurez-vous d'avoir un plan pour savoir quoi faire quand cela se produit. Vous devrez libérer de la mémoire (en supprimant les références aux objets) avant d'allouer d'autres objets, ou vous manquerez de mémoire. Parfois, le simple fait de dérouler la pile de quelques images le fera pour vous, parfois vous devrez faire quelque chose de plus explicite.

1
Keith Randall