37 votes

Libération explicite de la mémoire en c#

J'ai créé une application c# qui utilise 150mb de mémoire (private bytes), principalement à cause d'un gros dictionnaire :

Dictionary<string, int> Txns = new Dictionary<string, int>();

Je me demandais comment libérer cette mémoire. J'ai essayé ceci :

Txns = null;
GC.Collect();

Mais cela ne semble pas avoir d'incidence sur mes octets privés, qui passent de 155 à 145 mégaoctets. Des indices ?

Gracias

-édition-

D'accord, j'ai plus de chance avec ce code (il réduit le nombre d'octets privés à 50mb), mais pourquoi ?

Txns.Clear(); // <- makes all the difference
Txns = null;
GC.Collect();

-édition-

D'accord pour tous ceux qui disent "n'utilisez pas GC.collect", c'est juste (je ne vais pas en débattre, sauf pour dire que vous pouvez voir mon expérience en C), mais cela ne répond pas vraiment à ma question : Pourquoi le garbage collector ne libère-t-il la mémoire que si j'efface d'abord la liste des transactions ? Ne devrait-il pas libérer la mémoire de toute façon, puisque le dictionnaire a été déréférencé ?

19voto

Brian Rasmussen Points 68853

Les octets privés reflètent l'utilisation de la mémoire du processus. Lorsque des objets sont collectés, le segment de mémoire associé peut ou non être libéré pour le système d'exploitation. Le CLR gère la mémoire au niveau du système d'exploitation et, comme l'allocation et la libération de la mémoire ne sont pas gratuites, il n'y a aucune raison de libérer chaque morceau de mémoire immédiatement, car il y a de fortes chances que l'application demande plus de mémoire ultérieurement.

12voto

Adinochestva Points 4459

Si vous appelez GC.Collect(), il commence à faire son travail, mais il retourne immédiatement, il ne bloque pas, donc vous ne voyez pas son effet, si vous appelez GC.WaitForPendingFinalizers() après cela, il bloquera votre application jusqu'à ce que GC.Collect() finisse son travail.

6voto

David Schmitt Points 29384

Il est très probable que vous ayez une référence cachée au dictionnaire à un autre endroit. Le dictionnaire n'est donc pas collecté, mais si vous Clear() le contenu est collecté.

Comme d'autres l'ont déjà fait remarquer, il n'est pas recommandé de forcer le CG. Cela pourrait conduire à pousser la mémoire dans des "générations" plus élevées qui ne sont pas souvent collectées, gaspillant ainsi plus de mémoire qu'il n'y en a de gagnée à long terme.

4voto

peSHIr Points 3911

De mémoire, je ne sais pas si Dictionary a une Dispose() ou non, mais il est certain qu'il y aura une Clear() . Appelez l'une ou l'autre de ces méthodes avant de définir des références à null .

Il suffit ensuite de laisser le ramasse-miettes faire son travail. Il est presque jamais une bonne idée d'appeler GC.Collect() Si vous vous montrez explicite, il se peut qu'il ne fasse pas ce que vous voulez, ce dont vous avez besoin ou ce que vous attendez et qu'il vous coûte en termes de performances. L'analyse statique du code (=FxCop) ne vous avertit pas avec les éléments suivants Règle de fiabilité CA2001 pour rien, tu sais ? Ne le faites que si vous savez vraiment ce que vous faites. Et même dans ce cas, ne le faites pas. ;-)

Êtes-vous sûr que le dictionnaire est si grand que cela ? N'occupe-t-il pas seulement 10 Mo de mémoire, le reste étant occupé par votre application ? Question qui pourrait vous aider : Avez-vous déjà utilisé un profileur pour voir où la mémoire est réellement consommée ?

1voto

Chris Points 3290

Edita:

Pour être juste, le fait de mettre la référence à null ne libère pas la mémoire, il assigne son conteneur à une adresse différente, dans ce cas null. D'après MSDN , appelant Clear() C'est ce qu'il fait : "La propriété Count est fixée à 0 et les références à d'autres objets provenant d'éléments de la collection sont également libérées. La capacité reste inchangée."

...

Il ne faut jamais appeler le ramasse-miettes. Vous utilisez des objets gérés sans ressources natives, faites confiance au ramasse-miettes pour faire le ménage après vous.

Outre la taille de votre dictionnaire, vous n'avez pas à vous préoccuper de la mémoire, car la mémoire n'est pas votre problème, c'est celui des éboueurs.

Appel Clear() supprimera les références à tout objet contenu à l'intérieur, mais la capacité restera inchangée.

D'un point de vue technique, la collecte de la mémoire est une opération coûteuse et qui prend beaucoup de temps. En effet, non seulement le GC gère la mémoire du tas et nettoie votre tas, mais il défragmente également le tas. Il tente de déplacer la mémoire dans des blocs contigus afin d'accélérer l'allocation lorsqu'un morceau de code fait une demande importante.

p.s. Quelle est la taille de votre dictionnaire pour que vous utilisiez 155MB de mémoire ?

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