J'ai le code suivant:
MemoryStream foo(){
MemoryStream ms = new MemoryStream();
// write stuff to ms
return ms;
}
void bar(){
MemoryStream ms2 = foo();
// do stuff with ms2
return;
}
Y a-t-il une chance que le MemoryStream que j'ai alloué échoue d'une manière ou d'une autre à être détruit plus tard?
J'ai un examen par les pairs qui insiste pour que je ferme manuellement cela, et je ne trouve pas les informations pour dire s'il a un point valide ou non.
c#
.net
memory-leaks
memorystream
Codeur
la source
la source
Réponses:
Si quelque chose est jetable, vous devez toujours le jeter. Vous devriez utiliser une
using
déclaration dans votrebar()
méthode pour vous assurer qu'ellems2
est éliminée.Il sera éventuellement nettoyé par le garbage collector, mais il est toujours recommandé d'appeler Dispose. Si vous exécutez FxCop sur votre code, il le signalera comme un avertissement.
la source
Vous ne fuirez rien - du moins dans l'implémentation actuelle.
L'appel de Dispose ne nettoiera pas plus rapidement la mémoire utilisée par MemoryStream. Il va arrêter votre flux d'être viable en lecture / écriture des appels après l'appel, qui peut ou peut ne pas être utile pour vous.
Si vous êtes absolument sûr de ne jamais vouloir passer d'un MemoryStream à un autre type de flux, cela ne vous fera aucun mal de ne pas appeler Dispose. Cependant, c'est généralement une bonne pratique en partie parce que si jamais vous changez pour utiliser un autre Stream, vous ne voulez pas être mordu par un bogue difficile à trouver parce que vous avez choisi la solution de facilité dès le début. (D'un autre côté, il y a l'argument YAGNI ...)
L'autre raison de le faire de toute façon est qu'une nouvelle implémentation peut introduire des ressources qui seraient libérées sur Dispose.
la source
IDisposable
est un cas particulier allant à l'encontre des meilleures pratiques normales, vous pouvez faire valoir que c'est ce cas que vous ne devriez pas faire avant d'en avoir vraiment besoin, dans le cadre du YAGNI principe.Oui, il y a une fuite , en fonction de la façon dont vous définissez FUITE et de combien plus tard vous voulez dire ...
Si par fuite vous entendez "la mémoire reste allouée, indisponible pour une utilisation, même si vous avez fini de l'utiliser" et que vous entendez par la dernière fois à tout moment après avoir appelé dispose, alors oui il peut y avoir une fuite, bien que ce ne soit pas permanent (c'est-à-dire pour la durée de vie de vos applications).
Pour libérer la mémoire managée utilisée par MemoryStream, vous devez l' annuler en annulant votre référence à celle-ci, afin qu'elle devienne immédiatement éligible pour le garbage collection. Si vous ne le faites pas, vous créez une fuite temporaire à partir du moment où vous avez fini de l'utiliser, jusqu'à ce que votre référence soit hors de portée, car entre-temps la mémoire ne sera pas disponible pour l'allocation.
L'avantage de l'instruction using (par rapport à un simple appel à disposer) est que vous pouvez DÉCLARER votre référence dans l'instruction using. Lorsque l'instruction using se termine, non seulement Dispose est appelé, mais votre référence sort de la portée, annulant effectivement la référence et rendant immédiatement votre objet éligible au garbage collection sans que vous ayez à vous rappeler d'écrire le code "reference = null".
Si le fait de ne pas déférer tout de suite quelque chose n'est pas une fuite de mémoire "permanente" classique, cela a certainement le même effet. Par exemple, si vous conservez votre référence au MemoryStream (même après avoir appelé dispose), et un peu plus loin dans votre méthode, vous essayez d'allouer plus de mémoire ... la mémoire utilisée par votre flux mémoire encore référencé ne sera pas disponible jusqu'à ce que vous annuliez la référence ou qu'elle soit hors de portée, même si vous avez appelé dispose et que vous avez fini de l'utiliser.
la source
L'appel
.Dispose()
(ou l'encapsulation avecUsing
) n'est pas requis.La raison pour laquelle vous appelez
.Dispose()
est de libérer la ressource dès que possible .Pensez en termes, par exemple, au serveur Stack Overflow, où nous avons un ensemble limité de mémoire et des milliers de requêtes entrantes. Nous ne voulons pas attendre la récupération de place planifiée, nous voulons libérer cette mémoire dès que possible afin qu'elle soit disponible pour les nouvelles demandes entrantes.
la source
FileStream
objets et un autre pour lesMemoryStream
objets?Cela a déjà été répondu, mais j'ajouterai simplement que le bon vieux principe de masquage d'informations signifie que vous voudrez peut-être à un moment donné refactoriser:
à:
Cela met l'accent sur le fait que les appelants ne doivent pas se soucier du type de Stream renvoyé, et permet de changer l'implémentation interne (par exemple lors de la simulation pour les tests unitaires).
Vous devrez alors avoir des problèmes si vous n'avez pas utilisé Dispose dans votre implémentation de barre:
la source
Tous les flux implémentent IDisposable. Enveloppez votre flux de mémoire dans une déclaration d'utilisation et tout ira bien. Le bloc using garantira que votre flux est fermé et supprimé quoi qu'il arrive.
partout où vous appelez Foo, vous pouvez le faire en utilisant (MemoryStream ms = foo ()) et je pense que vous devriez toujours être ok.
la source
Vous ne fuirez pas de mémoire, mais votre réviseur de code a raison d'indiquer que vous devez fermer votre flux. C'est poli de le faire.
La seule situation dans laquelle vous pourriez perdre de la mémoire est lorsque vous laissez accidentellement une référence au flux et ne le fermez jamais. Vous n'êtes toujours pas une fuite de mémoire vraiment, mais vous êtes étendez inutilement la quantité de temps que vous prétendez l'utiliser.
la source
Je recommanderais d'encapsuler le MemoryStream
bar()
dans uneusing
instruction principalement pour la cohérence:.Dispose()
, mais il est possible qu'à un moment donné dans le futur, il le soit, ou vous (ou quelqu'un d'autre dans votre entreprise) puissiez le remplacer par votre propre MemoryStream personnalisé, etc.Une autre chose que je fais habituellement dans des cas comme
foo()
lors de la création et du retour d'un IDisposable est de m'assurer que tout échec entre la construction de l'objet et lereturn
est intercepté par une exception, supprime l'objet et renvoie l'exception:la source
Si un objet implémente IDisposable, vous devez appeler la méthode .Dispose lorsque vous avez terminé.
Dans certains objets, Dispose signifie la même chose que Fermer et vice versa, dans ce cas, l'un ou l'autre est bon.
Maintenant, pour votre question particulière, non, vous ne fuirez pas de mémoire.
la source
Je ne suis pas un expert .net, mais peut-être que le problème ici est les ressources, à savoir le descripteur de fichier, et non la mémoire. Je suppose que le ramasse-miettes finira par libérer le flux et fermer la poignée, mais je pense qu'il serait toujours préférable de le fermer explicitement, pour vous assurer de vider le contenu sur le disque.
la source
L'élimination des ressources non gérées n'est pas déterministe dans les langages de récupération de place. Même si vous appelez Dispose explicitement, vous n'avez absolument aucun contrôle sur le moment où la mémoire de sauvegarde est réellement libérée. Dispose est implicitement appelé lorsqu'un objet sort de la portée, que ce soit en quittant une instruction using ou en faisant apparaître la pile d'appels à partir d'une méthode subordonnée. Tout cela étant dit, parfois l'objet peut en fait être un wrapper pour une ressource gérée (par exemple un fichier). C'est pourquoi il est recommandé de fermer explicitement les instructions finally ou d'utiliser l'instruction using. À votre santé
la source
MemorySteram n'est rien d'autre qu'un tableau d'octets, qui est un objet géré. Oubliez de jeter ou de fermer cela n'a aucun effet secondaire autre que sur la tête de la finalisation.
Vérifiez simplement le constuctor ou la méthode de rinçage de MemoryStream dans le réflecteur et vous comprendrez pourquoi vous n'avez pas à vous soucier de sa fermeture ou de sa mise au rebut autrement que pour suivre les bonnes pratiques.
la source