60 votes

Est-il possible d'attraper une exception d'absence de mémoire en java ?

Je suis en train de développer un programme qui nécessiterait une quantité énorme de mémoire, et je veux attraper quand une exception hors-mémoire se produit. J'ai entendu dire que ce n'était pas possible de le faire, mais je suis curieux de savoir s'il y a du développement dans ce domaine.

2 votes

Demander comment gérer l'épuisement de la mémoire n'est pas tout à fait la même chose que demander s'il est possible d'attraper un message d'erreur de type OutOfMemoryError . Donc, ce n'est pas tout à fait une copie de Comment gérer OutOfMemoryError en Java ? .

92voto

ChssPly76 Points 53452

Ce n'est pas une exception, c'est une erreur : Erreur de mémoire (java.lang.OutOfMemoryError)

Vous peut l'attraper lorsqu'il descend 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 assez spécifiques (allouer des tonnes de choses dans une section de code spécifique, par exemple), vous ne serez probablement pas en mesure de l'attraper car vous ne saurez pas d'où il sera lancé.

18 votes

De plus, il n'y a probablement aucun moyen facile pour vous de vous en remettre si vous l'attrapez.

0 votes

@matt b - dans le cas spécifique où vous êtes capable pour l'attraper, vous essayez vraisemblablement de contrôler votre consommation de mémoire et vous seriez donc en mesure d'en libérer une partie ou la totalité. Mais d'une manière générale, vous avez raison, bien sûr.

1 votes

@ChssPly76 (et d'autres) - veuillez lire ma réponse pour comprendre pourquoi essayer de gérer la consommation de mémoire en capturant les OOME serait une erreur. MAUVAISE IDEE .

63voto

Suraj Chandran Points 12859

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
}

12 votes

Il y a est au moins une chose raisonnable que vous pourriez faire qui cause un OOME et qui est récupérable : Le chargement d'une très grande image. La seule chose dans le bloc try est un appel à ImageIO.read(), et vous montrez à l'utilisateur un dialogue lui disant que l'image est trop grande dans le bloc catch. Je dis ça comme ça...

3 votes

@uckelman C'est une mauvaise approche, sauf si votre application est monofilaire. Le problème est que même si votre thread de chargement d'image attrape OOME, les autres threads ne le savent pas et peuvent obtenir un OOME aussi.

5 votes

@SurajChandran : L'OOME causée par la tentative de chargement d'une image très grande sera due à la tentative d'allocation d'un très grand byte[] ou int[] . Vous obtenez un OOME parce que l'allocation échoue, et non pas parce que vous êtes réellement à court de mémoire - c'est pourquoi cela ne posera pas de problème aux autres threads.

28voto

Stephen C Points 255558

Vous pouvez attraper et tenter de récupérer les exceptions OutOfMemoryError (OOM), MAIS C'EST PROBABLEMENT UNE MAUVAISE IDÉE ... surtout si votre objectif est que l'application "continue".

Il y a plusieurs 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 les choses ; c'est-à-dire utiliser SoftReference et WeakReference pour les objets qui pourraient être libérés si la mémoire est courte.

  2. Si vous attendez d'être à court de mémoire pour libérer de la mémoire, votre application risque de passer plus de temps à faire tourner le ramasse-miettes. Selon la version de votre JVM et les paramètres de réglage de votre GC, la JVM peut finir par faire tourner le GC de plus en plus fréquemment à mesure qu'elle se rapproche du point où elle lancera un OOM. Le ralentissement (en termes de travail utile de l'application) 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 y a de fortes chances que la capture et la récupération de l'OOM ne permettent pas de récupérer la mémoire perdue. Votre application continuera à fonctionner pendant un certain temps, puis connaîtra une nouvelle panne, et encore, et encore, à des intervalles de plus en plus courts.

Mon conseil est donc de ne PAS essayer de continuer à partir d'une panne... sauf si vous connaître :

  • où et pourquoi la panne s'est produite,
  • qu'il n'y aura pas eu de "dommages collatéraux", et
  • que votre récupération libérera assez de mémoire pour continuer.

14voto

bitflung Points 1

Je voulais juste dire ceci pour tous ceux qui se demandent pourquoi quelqu'un peut manquer de mémoire : je travaille sur un projet qui manque fréquemment de mémoire et j'ai dû mettre en place une solution pour cela.

le projet est un composant d'une application de médecine légale et d'investigation. après avoir collecté des données sur le terrain (en utilisant une empreinte mémoire très faible, d'ailleurs), les données sont ouvertes dans notre application d'investigation. une des fonctionnalités est d'effectuer une traversée CFG de n'importe quelle image binaire arbitraire qui a été capturée sur le terrain (applications de la mémoire physique). ces traversées peuvent prendre beaucoup de 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 que possible en mémoire physique, mais les structures de données grandissent en même temps que le binaire et nous ne pouvons pas tout garder en mémoire (le but est d'utiliser un tas java inférieur à 256m). alors que faire ?

J'ai créé des versions de LinkedLists, Hashtables, etc. sauvegardées sur disque. Ces versions sont des remplacements immédiats de leurs homologues et mettent en œuvre toutes les mêmes interfaces, de sorte qu'elles semblent identiques de l'extérieur.

la différence ? ces structures de remplacement coopèrent les unes avec les autres, en détectant les erreurs de mémoire et en 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. libérer l'élément le dépose sur le disque dans un fichier temporaire (dans le répertoire temp fourni par le système) et marque un objet de remplacement comme "paginé" dans la collection appropriée.

il y a des PLIEUX de raisons pour lesquelles vous pouvez manquer de mémoire dans une application java - la Racine de la plupart de ces raisons est l'une ou l'autre ou les deux : 1. L'application fonctionne sur une machine à ressources limitées (ou tente de limiter l'utilisation des ressources en limitant la taille du tas). 2. L'application nécessite simplement de grandes quantités de mémoire (l'édition d'images 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 ? qu'en est-il des collecteurs de données à long terme sans stockage non-volatile ?)

-bit

0 votes

Ce type de logique semble être un cas d'utilisation parfait pour les classes de "référence" comme WeakReference. stackoverflow.com/a/1692369/29924

8voto

Hardcoded Points 2786

Il est possible d'attraper un OutOfMemoryError (C'est un Error et non un Exception ), mais vous devez savoir qu'il n'y a aucun moyen d'obtenir un comportement défini.
Vous risquez même d'obtenir une autre OutOfMemoryError en essayant de l'attraper.

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

2 votes

"il n'y a aucun moyen d'obtenir un comportement défini" : parce que OutOfMemoryError peuvent être lancés n'importe où, y compris dans des endroits qui pourraient laisser votre programme dans un état incohérent. Voir stackoverflow.com/questions/8728866/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X