2009-09-02 9 views
1

J'essaye de charger une image dans la mémoire mais pourrais avoir des problèmes de mémoire puisque j'ai d'autres images chargées. Ces images ont un champ "visible" qui dicte si elles sont visibles ou non. Indépendamment de la visibilité, je les garde en mémoire pour un chargement rapide (quand ils redeviennent visibles).Quelle est la meilleure façon de gérer ce cas "try-error-clean -retry"?

Mais comme j'ai beaucoup d'entre eux en mémoire je veux essayer de charger une nouvelle image et si je rencontre des problèmes de mémoire, libérez les images non visibles et essayez à nouveau. Maintenant, à ce jour, je me sers de ce assez laid (et le mal pour une raison quelconque, je suis sûr) morceau de code:

try { 
    image = GraphicsUtilities.loadImage(filePath); 
} catch (OutOfMemoryError e) { 
    removeHiddenImageReferences(); 
    try { 
     image = GraphicsUtilities.loadImage(filePath); 
    } catch (OutOfMemoryError ee) { 
     ee.printStackTrace(); 
     JOptionPane.showMessageDialog(parent, 
      "There is not enought memory to load this image", 
      "Not enough memory", JOptionPane.WARNING_MESSAGE); 
    } 
} 

Ma question est, comment dois-je gérer ce genre de cas? Je pense qu'attraper une exception et récupérer une exception dans la clause catch est mauvais.

Répondre

4

Je ne vois pas cela comme un style particulièrement mauvais - tout le point de la clause "catch" est de gérer la cause de l'exception. Dans ce cas, vous choisissez de gérer un manque de mémoire en libérant un peu, puis en autorisant une nouvelle tentative avant de propager une erreur. Cela semble parfaitement raisonnable - vous pouvez le réécrire de différentes façons syntaxiquement contournées pour éviter d'avoir du code dans la clause catch, mais pourquoi s'en soucier? Cela exprime clairement votre intention. Cependant, une modification de conception qui pourrait être logique consisterait à renvoyer l'exception dans le second cas (ou, tout simplement, ne pas l'attraper), et disposer d'un gestionnaire d'exceptions plus global pour gérer la mémoire complète. Même cela est discutable - si vous n'attendez pas vraiment d'autres situations OutOfMemory, alors le gérer à proximité du scénario qui le cause (presque) toujours est raisonnable.

1

Introduisez une boucle while pour que votre nouvelle tentative soit liée à une condition, et pas seulement à l'exception levée.

int tryCount = 2; 
while (tryCount > 0) { 
    try { 
    image = GraphicsUtilities.loadImage(filePath); 
    } catch (OutOfMemoryError e) { 
    removeHiddenImageReferences(); 
    tryCount--; 
    } 
} 
if(tryCount <= 0) { 
     JOptionPane.showMessageDialog(parent, 
      "There is not enought memory to load this image", 
      "Not enough memory", JOptionPane.WARNING_MESSAGE); 
} 

Cet exemple manque le stacktrace, mais à ce stade, il est pas important parce que vous êtes hors de la mémoire (il suffit d'inclure un identifiant dans le MessageDialog ou ouvrir une session où cette vérification est faite).

+0

merci pour la réponse. J'utiliserais ceci si je devais libérer graduellement la mémoire (peut-être libérer une image cachée à la fois) mais puisque dans mon exemple je libère seulement une fois je pense que c'est un peu exagéré. –

2

Une option serait de le décomposer en 2 méthodes, vous appelez LoadImage qui appelle TryLoadImage en interne.

public void TryLoadImage(string filePath){ 
    bool b = false; 

    try{ 
      image = GraphicsUtilities.loadImage(filePath); 
      bool b = true; 
    } 
    catch(OutOfMemoryError){ 
      // Log notfication of file the was too big perhaps? so in the future you could 
      // optimize this? 
    } 
} 

public void LoadImage(string filePath, bool clearReferences){ 

     if(!TryLoadImage(string filePath))  
     { 
      removeHiddenImageReferences(); 
      if(!TryLoadImage(string filePath)){ 
        // Log error 
        JOptionPane.showMessageDialog .... 
      } 
     } 
} 
+0

Bonne alternative ... En fait, j'aurais dû formuler ma réponse différemment. Je ne m'intéressais pas seulement à la façon de le coder (votre réponse est vraiment bonne), mais si mon design a été "mal" écrit dessus. Je commence à penser que pour mon exemple simple, ma solution pourrait être la plus facile à écrire et à maintenir. –

+0

Je ne pense pas que la façon dont vous le faites est mauvaise, il suffit de noter quelque chose chaque fois que vous obtenez une exception Out of Mana plutôt que de le jeter complètement, de sorte que vous pouvez surveiller les performances. –

3

C'est dur, comme OutOfMemoryError s ne sont pas spécifiques à l'individu Threads. Cela signifie que, bien que dans le Thread actuel, vous chargiez une image qui prend la plus grande partie de la mémoire de votre processus, un autre Thread peut exécuter le processus qui déclenche réellement le OutOfMemoryError. L'idée d'Adam Wright d'un gestionnaire OOME plus global serait quelque chose à considérer si vous avez besoin de gérer ce cas en cours.

modifier:

This article parle de la mise en place d'un système d'avertissement de mémoire, de sorte que les auditeurs peuvent être alertés avant de déclencher le oome. Cela vous permet de prendre des mesures préventives et de sauvegarder votre système de l'OOME débilitant. Après avoir lu votre commentaire, je poste le lien ici pour la postérité.

+0

hm n'a pas pensé à ça. mais heureusement dans mon cas au moment où cette méthode est appelée seulement l'EDT est exécuté donc je suis bon. Mais je devrais faire une note dans le cas général. –

1

Avez-vous envisagé d'utiliser SoftReference? Bien que cela ne changerait pas nécessairement votre code ici, cela rendrait la situation plus évolutive si votre application faisait autre chose et vous seriez prêt à larguer ces images si elle manquait de mémoire ailleurs.

-1

Vous pouvez appeler

removeHiddenImageReferences(); 

premier. Ensuite, vous avez seulement besoin d'un essai/catch. Il est inutile d'optimiser, à moins que vous sachiez que removeHiddenImageReferences() est horriblement lent (comme si vous travaillez avec des millions d'objets). Habituellement, vous ne pouvez pas en faire trop sur le manque de mémoire de toute façon.

+0

le point entier est de ne pas appeler removeHiddenImageReferences(); si je ne dois pas. Je veux garder autant d'images en mémoire que possible et ne libérer de la mémoire qu'en cas de besoin –

+0

Désolé, je viens de lire votre code et suis allé directement à répondre sans vraiment lire votre question :) – Shizzmo

Questions connexes