2009-07-01 7 views
1

J'ai un tel code:vendrons vraiment libérer la mémoire s'il y a d'autres objets pointant vers elle?

public class A: IDisposable 
    { 
     public CPlusCode cPlusCode{get;set;} 

    public void CallB() 
    { 
     using(bCode = new B(cPlusCode)) 
     { 
       //do everything in B 
     } 
    } 

    public void Dispose() 
    { 
     cPlusCode.Dispose(); 
    } 
    } 

    public class B: IDisposable 
    { 
    private CPlusCode cpp; 
     public B(CPlusCode cPlus) 
    { 
    cpp= cPlus; 
    } 
    public void Dispose() 
    { 
    cpp.Dispose(); 
    //dispose everything 
    } 
    } 

    public static void Main() 
    { 
      for(int i=0; i<100000; i++) 
       { 
         var aObject = new A(); 
        aObject .CallB(); 
       } 
    } 

Le problème est que quand j'exécute Main et B mange beaucoup de mémoire à instancier, et de mon observation, il semble que la mémoire consommée par le programme n'est pas libéré.

vendrons vraiment libérer la mémoire s'il y a d'autres objets pointant vers elle?

+0

Vous ne devriez probablement pas disposer de la ressource dans B, sauf si elle fait une copie de la ressource ou en alloue une nouvelle elle-même. La façon dont le code est écrit, appeler CallB() deux fois sur le même objet entraînerait une exception. –

Répondre

2

Le CPG s'exécutera lorsqu'il le jugera nécessaire, de sorte que le 'temps opportun' n'est pas pertinent. Cela arrivera quand cela arrivera; c'est-à-dire qu'il est non-déterministe

6

IDisposable n'a rien à voir avec la récupération de la mémoire gérée. IDisposable permet de libérer des ressources types non gérées par la collecte des ordures comme les poignées etc. Pour les types normaux .NET, le garbage collector se chargera de récupérer la mémoire lorsque les objets ne sont plus référencés.

+0

Désolé! Je modifie la question pour la rendre plus claire – Graviton

0

de mon observation, il semble que la mémoire mangée par le programme ne libéré.

Ceci est parfaitement normal. Le programme se bloque à une certaine quantité de mémoire inutilisée, ce qui sera publié si le système a vraiment besoin.

On pourrait penser que la meilleure chose à faire est de garder la mémoire aussi petite que possible, mais c'est en fait l'inverse. L'ordinateur ne profite pas quoi que ce soit d'avoir beaucoup de mémoire utilisé, donc pour une meilleure performance de l'application ne doit pas faire le travail supplémentaire pour minimiser l'utilisation de la mémoire jusqu'à ce qu'il soit vraiment nécessaire.

vendrons vraiment libérer la mémoire si il y a d'autres objets pointant vers il?

Oui et non ...

appeler Dispose sur un objet ne libère pas l'objet lui-même, si l'objet contient d'autres objets, ceux-ci peuvent être libérés par la méthode Dispose. Cela ne libèrera pas de mémoire par lui-même, mais il permettra au garbage collector de le faire lors de la prochaine exécution.

2

Dispose est juste une méthode. Cela n'a rien à faire du tout.

Après avoir appelé Dispose sur un objet, l'objet existe toujours, mais ne peut plus être utilisé en toute sécurité. Cependant, le runtime n'aide pas à l'appliquer. Une implémentation "solide" de Dispose (une conçue pour aider à attraper les bogues) placerait un drapeau _disposed à l'intérieur de l'objet à vrai, et chaque autre méthode sur l'objet lancerait ObjectDisposedException si cet indicateur est vrai (la méthode Dispose elle-même devrait ignorer silencieusement autres appels). Mais il appartient totalement à l'opérateur de mettre en œuvre ce modèle.

Un exemple serait FileStream. Lorsqu'il a un fichier ouvert, le nombre de handles du processus aura augmenté de 1. Lorsque vous appelez Dispose, le nombre de handles diminuera. Mais ceci est seulement parce que l'auteur de FileStream écrit leur méthode Dispose pour y arriver.

Ce qui conduit au prochain problème - vous pouvez voir le nombre de handles du processus dans le Gestionnaire des tâches et c'est un compteur très simple, mais comment mesurez-vous l'utilisation de la mémoire? Notez que les nombres affichés dans le Gestionnaire des tâches sont loin d'être simples.

+1

Je préfère jeter une ObjectDisposedException, mais je suis totalement d'accord avec le reste. http://msdn.microsoft.com/fr-fr/library/system.objectdisposedexception.aspx –

+0

Eh bien, je ne savais pas qu'il y avait une exception spécifique pour ça. Mise à jour de la réponse –

0

Si vous l'avez implémenté correctement et que vous libérez toutes les ressources non gérées dans Dispose(), l'objet doit être collecté (ou mieux, sera éligible pour la collecte) après avoir libéré toutes les références à cet objet.

Notez toutefois que vous ne disposez pas de l'objet A dans votre exemple, qui est également IDisposable. Si A contient une référence à B et que vous ne disposez pas de A, cela peut également retarder la collecte de B (dans le cas où A contient des éléments non gérés pouvant créer une référence à A).

Depuis code non managé semble être référencé par A dans votre exemple, A devrait être responsable de le disposer.

Questions connexes