Ich habe folgenden Code:
MemoryStream foo(){
MemoryStream ms = new MemoryStream();
// write stuff to ms
return ms;
}
void bar(){
MemoryStream ms2 = foo();
// do stuff with ms2
return;
}
Gibt es eine Chance, dass der von mir zugewiesene MemoryStream später nicht mehr entsorgt wird?
Ich habe eine Peer Review, die darauf besteht, dass ich dies manuell schließe, und ich kann keine Informationen finden, um festzustellen, ob er einen gültigen Punkt hat oder nicht.
c#
.net
memory-leaks
memorystream
Codierer
quelle
quelle
Antworten:
Wenn etwas wegwerfbar ist, sollten Sie es immer entsorgen. Sie sollten eine
using
Anweisung in Ihrerbar()
Methode verwenden, um sicherzustellen, dassms2
Disposed wird.Es wird schließlich vom Garbage Collector aufgeräumt, aber es ist immer eine gute Praxis, Dispose aufzurufen. Wenn Sie FxCop für Ihren Code ausführen, wird dies als Warnung gekennzeichnet.
quelle
Sie werden nichts verlieren - zumindest in der aktuellen Implementierung.
Durch Aufrufen von Dispose wird der von MemoryStream verwendete Speicher nicht schneller bereinigt. Dadurch wird verhindert, dass Ihr Stream nach dem Aufruf für Lese- / Schreibanrufe geeignet ist, was für Sie möglicherweise nützlich ist oder nicht.
Wenn Sie absolut sicher sind, dass Sie niemals von einem MemoryStream zu einer anderen Art von Stream wechseln möchten, schadet es Ihnen nicht, Dispose nicht aufzurufen. Allerdings ist es im Allgemeinen gute Praxis zum Teil , weil , wenn Sie jemals tun Änderung einen anderen Strom zu verwenden, Sie wollen nicht von einer schwer zu finden Bug gebissen werden , weil Sie den einfachen Weg gewählt haben sehr frühe Phase. (Auf der anderen Seite gibt es das YAGNI-Argument ...)
Der andere Grund dafür ist, dass eine neue Implementierung möglicherweise Ressourcen einführt, die bei Dispose freigegeben würden.
quelle
IDisposable
wird , nicht zu entsorgen, ein Sonderfall ist, der gegen die üblichen Best Practices verstößt, könnten Sie argumentieren, dass Sie diesen Fall im YAGNI erst dann tun sollten, wenn Sie es wirklich brauchen Prinzip.Ja, es gibt ein Leck , abhängig davon, wie Sie LEAK definieren und wie viel SPÄTER Sie meinen ...
Wenn mit Leck gemeint ist, dass "der Speicher zugewiesen bleibt und nicht zur Verwendung verfügbar ist, obwohl Sie ihn nicht mehr verwenden", und mit letzterem meinen Sie jederzeit nach dem Aufruf von dispose, dann kann es ja zu einem Leck kommen, obwohl es nicht dauerhaft ist (dh für die Lebensdauer Ihrer Anwendungslaufzeit).
Um den vom MemoryStream verwendeten verwalteten Speicher freizugeben , müssen Sie die Referenzierung aufheben , indem Sie Ihren Verweis darauf ungültig machen , damit er sofort für die Speicherbereinigung in Frage kommt. Wenn Sie dies nicht tun, erstellen Sie ab dem Zeitpunkt, an dem Sie es verwendet haben, ein temporäres Leck, bis Ihre Referenz den Gültigkeitsbereich verlässt, da der Speicher in der Zwischenzeit nicht für die Zuordnung verfügbar ist.
Der Vorteil der using-Anweisung (gegenüber dem einfachen Aufruf von dispose) besteht darin, dass Sie Ihre Referenz in der using-Anweisung deklarieren können. Wenn die using-Anweisung beendet ist, wird nicht nur dispose aufgerufen, sondern Ihre Referenz verlässt den Gültigkeitsbereich, wodurch die Referenz effektiv ungültig wird und Ihr Objekt sofort für die Speicherbereinigung in Frage kommt, ohne dass Sie daran denken müssen, den Code "reference = null" zu schreiben.
Obwohl es kein klassisches "permanentes" Speicherleck ist, etwas nicht sofort zu entfernen, hat es definitiv den gleichen Effekt. Wenn Sie beispielsweise Ihren Verweis auf den MemoryStream beibehalten (auch nach dem Aufruf von dispose) und etwas weiter unten in Ihrer Methode versuchen, mehr Speicher zuzuweisen, ist der von Ihrem noch referenzierten Speicherstrom verwendete Speicher nicht verfügbar an Sie, bis Sie die Referenz ungültig machen oder sie außerhalb des Gültigkeitsbereichs liegt, obwohl Sie dispose aufgerufen haben und damit fertig sind.
quelle
Das Aufrufen
.Dispose()
(oder Umschließen mitUsing
) ist nicht erforderlich.Der Grund, den Sie aufrufen,
.Dispose()
besteht darin , die Ressource so schnell wie möglich freizugeben .Denken Sie beispielsweise an den Stack Overflow-Server, auf dem nur ein begrenzter Arbeitsspeicher und Tausende von Anfragen eingehen. Wir möchten nicht auf die geplante Speicherbereinigung warten, sondern diesen Speicher so schnell wie möglich freigeben, damit er verfügbar ist für neue eingehende Anfragen.
quelle
FileStream
Objekten und einen anderen fürMemoryStream
Objekte zu verwenden?Dies ist bereits beantwortet, aber ich möchte nur hinzufügen, dass das gute altmodische Prinzip des Versteckens von Informationen bedeutet, dass Sie möglicherweise zu einem späteren Zeitpunkt eine Umgestaltung wünschen:
zu:
Dies unterstreicht, dass es Anrufern egal sein sollte, welche Art von Stream zurückgegeben wird, und ermöglicht es, die interne Implementierung zu ändern (z. B. beim Verspotten für Unit-Tests).
Sie müssen dann in Schwierigkeiten geraten, wenn Sie Dispose in Ihrer Balkenimplementierung nicht verwendet haben:
quelle
Alle Streams implementieren IDisposable. Wickeln Sie Ihren Speicher-Stream in eine using-Anweisung ein, und es wird Ihnen gut gehen. Der using-Block stellt sicher, dass Ihr Stream geschlossen und entsorgt wird, egal was passiert.
Wo immer du Foo aufrufst, kannst du es mit (MemoryStream ms = foo ()) machen und ich denke, du solltest immer noch in Ordnung sein.
quelle
Sie werden keinen Speicher verlieren, aber Ihr Code-Prüfer zeigt korrekt an, dass Sie Ihren Stream schließen sollten. Es ist höflich, dies zu tun.
Die einzige Situation, in der Sie möglicherweise Speicher verlieren, besteht darin, dass Sie versehentlich einen Verweis auf den Stream hinterlassen und ihn niemals schließen. Sie sind undicht noch nicht wirklich Speicher, aber Sie sind Verlängerung unnötig die Menge an Zeit , die Sie verwenden es verlangen.
quelle
Ich würde empfehlen, den MemoryStream hauptsächlich aus Gründen der Konsistenz
bar()
in eineusing
Anweisung einzuschließen :.Dispose()
, aber es ist möglich, dass dies irgendwann in der Zukunft der Fall ist oder dass Sie (oder eine andere Person in Ihrem Unternehmen) ihn durch Ihren eigenen benutzerdefinierten MemoryStream usw. ersetzen.Eine andere Sache, die ich normalerweise in Fällen wie
foo()
dem Erstellen und Zurückgeben eines IDisposable mache, ist sicherzustellen, dass ein Fehler zwischen dem Erstellen des Objekts und demreturn
durch eine Ausnahme abgefangen wird, das Objekt entsorgt und die Ausnahme erneut auslöst:quelle
Wenn ein Objekt IDisposable implementiert, müssen Sie die .Dispose-Methode aufrufen, wenn Sie fertig sind.
In einigen Objekten bedeutet Entsorgen dasselbe wie Schließen und umgekehrt. In diesem Fall ist beides gut.
Nun, für Ihre spezielle Frage, nein, Sie werden keinen Speicher verlieren.
quelle
Ich bin kein .net-Experte, aber vielleicht liegt das Problem hier in den Ressourcen, nämlich dem Dateihandle und nicht im Speicher. Ich denke, der Garbage Collector wird den Stream irgendwann freigeben und das Handle schließen, aber ich denke, es wäre immer die beste Vorgehensweise, ihn explizit zu schließen, um sicherzustellen, dass Sie den Inhalt auf die Festplatte spülen.
quelle
Die Entsorgung nicht verwalteter Ressourcen ist in Müllsammelsprachen nicht deterministisch. Selbst wenn Sie Dispose explizit aufrufen, haben Sie absolut keine Kontrolle darüber, wann der Sicherungsspeicher tatsächlich freigegeben wird. Dispose wird implizit aufgerufen, wenn ein Objekt den Gültigkeitsbereich verlässt, sei es durch Beenden einer using-Anweisung oder durch Aufrufen des Callstacks von einer untergeordneten Methode. Dies alles gesagt, manchmal kann das Objekt tatsächlich ein Wrapper für eine verwaltete Ressource (z. B. Datei) sein. Aus diesem Grund empfiehlt es sich, in finally-Anweisungen explizit zu schließen oder die using-Anweisung zu verwenden. Prost
quelle
MemorySteram ist nichts anderes als ein Array von Bytes, bei denen es sich um verwaltete Objekte handelt. Vergessen Sie zu entsorgen oder zu schließen, dies hat keine anderen Nebenwirkungen als über den Kopf der Finalisierung.
Überprüfen Sie einfach die Konstruktor- oder Spülmethode von MemoryStream im Reflektor, und es wird klar, warum Sie sich keine Gedanken über das Schließen oder Entsorgen machen müssen, außer nur, um bewährte Verfahren zu befolgen.
quelle