Was genau sind nicht verwaltete Ressourcen?

159

Ich möchte etwas über nicht verwaltete Ressourcen wissen. Kann mir bitte jemand eine Grundidee geben?

Deviprasad Das
quelle
Siehe auch diese Seite, die eine fantastische Erklärung und ein Muster für die ordnungsgemäße Verwendung von IDisposable und die Berücksichtigung nicht verwalteter Ressourcen enthält: stackoverflow.com/questions/538060/…
Kyle Baran

Antworten:

177

Verwaltete Ressourcen bedeuten im Grunde "verwalteten Speicher", der vom Garbage Collector verwaltet wird. Wenn Sie keine Verweise mehr auf ein verwaltetes Objekt haben (das verwalteten Speicher verwendet), gibt der Garbage Collector diesen Speicher (eventuell) für Sie frei.

Nicht verwaltete Ressourcen sind dann alles, was der Garbage Collector nicht weiß. Beispielsweise:

  • Dateien öffnen
  • Öffnen Sie Netzwerkverbindungen
  • Nicht verwalteter Speicher
  • In XNA: Scheitelpunktpuffer, Indexpuffer, Texturen usw.

Normalerweise möchten Sie diese nicht verwalteten Ressourcen freigeben, bevor Sie alle Verweise auf das Objekt verlieren, das sie verwaltet. Sie tun dies, indem Sie dieses DisposeObjekt aufrufen oder (in C #) die usingAnweisung verwenden, die den Aufruf Disposefür Sie übernimmt .

Wenn Sie DisposeIhre nicht verwalteten Ressourcen korrekt vernachlässigen , wird der Garbage Collector diese möglicherweise für Sie verarbeiten, wenn das Objekt, das diese Ressource enthält, Garbage Collected ist (dies ist "Finalisierung"). Da der Garbage Collector jedoch nichts über die nicht verwalteten Ressourcen weiß, kann er nicht sagen, wie dringend er freigegeben werden muss. Daher kann es sein, dass Ihr Programm eine schlechte Leistung erbringt oder keine Ressourcen mehr zur Verfügung stehen.

Wenn Sie eine Klasse selbst implementieren , dass Griffe Ressourcen unmanaged, ist es an Ihnen, zu implementieren Disposeund Finalizerichtig.

Andrew Russell
quelle
7
Offene Datenbankverbindung fällt unter welche Kategorie? Verwaltet / nicht verwaltet?
Deviprasad Das
8
+1 Andere Antworten übersehen den wichtigen Punkt, den Sie Dispose für ein verwaltetes Objekt aufrufen , das intern die Freigabe der nicht verwalteten Ressource übernimmt (z. B. Dateihandle, GDI + Bitmap, ...), und die, wenn Sie direkt auf nicht verwaltete Ressourcen zugreifen ( PInvoke etc.) müssen Sie damit umgehen.
Ian Mercer
2
@Dev: Nicht verwaltet - da der GC nichts davon weiß (vorausgesetzt, Sie verwenden keine hypothetische Datenbank mit verwaltetem Speicher). Das Verbindungsobjekt selbst enthält jedoch möglicherweise keine nicht verwaltete Ressource. Vermutlich verwendet die Datenbankverbindung irgendwo eine offene Datei oder Netzwerkverbindung - aber es ist möglich, dass ein anderes Objekt (außer dem Verbindungsobjekt) diese nicht verwaltete Ressource verarbeitet (möglicherweise speichert Ihre Datenbankbibliothek Verbindungen zwischen). Überprüfen Sie die Dokumentation und sehen Sie, wo Sie aufgefordert werden, anzurufen Disposeoder zu verwenden using.
Andrew Russell
11
Ich habe einen grundlegenden Kommentar / eine grundlegende Frage dazu. Kann ich ein Objekt als verwaltet / nicht verwaltet nur anhand des Typs verknüpfen? Beispiel: Zeichenfolge wird verwaltet, DataSet wird nicht verwaltet (weshalb es eine Dispose () -Methode hat.) , Datenbankverbindungen werden nicht verwaltet (weil sie entsorgt wurden) usw. Ist also die Annahme, dass eine "Dispose ()" - Methode nicht verwaltet wird? Was wäre darüber hinaus ein XmlDocument-Objekt? Danke
ganders
15
@ganders Das ist eine gute Faustregel. Beachten Sie jedoch, dass alle Instanzen der C # -Klasse verwaltete Objekte sind. Wenn eine Instanz einer Klasse nicht verwaltete Ressourcen enthalten kann, sollte diese Klasse implementiert werden IDisposable. Wenn eine Klasse nicht implementieren IDisposable, dann Sie sollten von Instanzen dieser Klasse verfügen mit usingoder Dispose()wenn Sie mit ihnen fertig sind. Auf dieser Grundlage gilt Ihre Umkehrung: Wenn eine Klasse implementiert wird IDisposable, enthält sie wahrscheinlich intern nicht verwaltete Ressourcen.
Andrew Russell
56

Einige Benutzer zählen offene Dateien, Datenbankverbindungen, zugewiesenen Speicher, Bitmaps, Dateistreams usw. zu den verwalteten Ressourcen, andere zu den nicht verwalteten. Werden sie also verwaltet oder nicht verwaltet?

Meiner Meinung nach ist die Antwort komplexer: Wenn Sie eine Datei in .NET öffnen, verwenden Sie wahrscheinlich eine integrierte .NET-Klasse System.IO.File, FileStream oder etwas anderes. Da es sich um eine normale .NET-Klasse handelt, wird sie verwaltet. Aber es ist ein Wrapper, der die "Drecksarbeit" erledigt (kommuniziert mit dem Betriebssystem über Win32-DLLs, ruft Funktionen auf niedriger Ebene oder sogar Assembler-Anweisungen auf), die die Datei wirklich öffnen. Und das ist, was .NET nicht weiß, nicht verwaltet. Sie können die Datei jedoch möglicherweise selbst öffnen, indem Sie Assembler-Anweisungen verwenden und die Funktionen der .NET-Datei umgehen. Dann sind das Handle und die geöffnete Datei nicht verwaltete Ressourcen.

Das Gleiche gilt für die Datenbank: Wenn Sie eine DB-Assembly verwenden, haben Sie Klassen wie DbConnection usw., die .NET bekannt sind und verwaltet werden. Aber sie verpacken die "schmutzige Arbeit", die nicht verwaltet wird (Speicher auf dem Server zuweisen, Verbindung herstellen, ...). Wenn Sie diese Wrapper-Klasse nicht verwenden und selbst einen Netzwerk-Socket öffnen und mit einigen Befehlen mit Ihrer eigenen seltsamen Datenbank kommunizieren, wird diese nicht verwaltet.

Diese Wrapper-Klassen (Datei, DbConnection usw.) werden verwaltet, verwenden jedoch nicht verwaltete Ressourcen auf dieselbe Weise wie Sie, wenn Sie die Wrapper nicht verwenden und die "Drecksarbeit" selbst ausführen. Und deshalb implementieren diese Wrapper Dispose / Finalize-Muster. Es liegt in ihrer Verantwortung, dem Programmierer zu ermöglichen, nicht verwaltete Ressourcen freizugeben, wenn der Wrapper nicht mehr benötigt wird, und sie freizugeben, wenn der Wrapper durch Müll gesammelt wird. Der Wrapper wird korrekt vom Garbage Collector gesammelt, aber die nicht verwalteten Ressourcen im Inneren werden mithilfe des Dispose / Finalize-Musters gesammelt.

Wenn Sie in Ihrer Klasse keine integrierten .NET- oder Drittanbieter-Wrapper-Klassen verwenden und Dateien nicht durch Assembler-Anweisungen usw. öffnen, werden diese geöffneten Dateien nicht verwaltet und Sie MÜSSEN das Dispose / Finalize-Muster implementieren. Wenn Sie dies nicht tun, kommt es zu einem Speicherverlust, einer für immer gesperrten Ressource usw., selbst wenn Sie diese nicht mehr verwenden (Dateivorgang abgeschlossen) oder sogar nachdem Ihre Anwendung beendet wurde.

Ihre Verantwortung liegt jedoch auch bei der Verwendung dieser Wrapper. Für diejenigen, die dispose / finalize implementieren (Sie erkennen, dass sie IDisposable implementieren), implementieren Sie auch Ihr dispose / finalize-Muster und entsorgen Sie sogar diese Wrapper oder geben Sie ihnen das Signal, ihre nicht verwalteten Ressourcen freizugeben. Wenn Sie dies nicht tun, werden die Ressourcen nach einer unbestimmten Zeit freigegeben, aber es ist sauber, sie sofort freizugeben (schließen Sie die Datei sofort und lassen Sie sie nicht offen und blockieren Sie sie zufällig für einige Minuten / Stunden). In der Dispose-Methode Ihrer Klasse rufen Sie also Dispose-Methoden aller verwendeten Wrapper auf.

Martas
quelle
1
Gut über die zusätzliche Klarheit aufunmanaged vs managed resources
jetzt wer nicht genannt werden darf.
Danke für deine Antwort. In welchen Klassen wird empfohlen, Dispose tatsächlich aufzurufen?
BKSpurgeon
2
Das ist einfach. Bei jeder Klasse, die Sie verwenden, müssen Sie überprüfen, ob die IDisposable-Schnittstelle implementiert ist. Wenn ja, wenn Sie eine solche Klasse in einer Methode verwenden (z. B. Öffnen einer Datei, Speichern von Text, Schließen der Datei), können Sie diese mit dem Muster () {} verwenden, das Dispose automatisch für Sie aufruft. Wenn Sie eine solche Klasse in mehr Methoden verwenden (z. B. Ihre Klasse enthält Datei, im Konstruktor öffnet sie die Datei, dann fügen mehrere Methoden einige Protokolle hinzu ...), müssen Sie die IDisposable-Schnittstelle von Ihrer Klasse implementieren und das Dispose / Finalize-Muster implementieren und entsorgen Sie das Objekt dieser Klasse ordnungsgemäß.
Martas
1
"... eine integrierte .NET-Klasse System.IO.File, FileStream oder etwas anderes. Da es sich um eine normale .NET-Klasse handelt, wird sie verwaltet." In Bezug auf Respekt ist dies falsch und irreführend. Sie werden nicht verwaltet . Wenn sie verwaltet würden, könnten Sie diese Klassen zuweisen und erwarten, dass der Garbage Collector die Freigabe aller Ressourcen auf deterministische Weise vollständig handhabt. Dies führt jedoch dazu, dass Dateihandles und nicht verwaltete Ressourcen viel länger als nötig gesperrt und gehalten werden, da der Garbage Collector die Zuordnung der Klasse nicht aufhebt und sie möglicherweise für eine sehr lange Zeit nicht finalisiert.
AaronLS
1
@AaronLS In Ihrem Kommentar haben Sie über "FileStream" gesprochen, indem Sie es als nicht verwaltet bezeichnet haben, aber nicht, obwohl es intern nicht verwaltete Ressourcen verwendet, um seine Arbeit zu erledigen. In der verwalteten Welt hat Microsoft viele nicht verwaltete Dinge vor Ihnen verborgen, indem es das implementiert hat Muster entsorgen. Verwalteter Code bedeutet nicht, dass keine nicht verwalteten Ressourcen verwendet werden. Microsoft hat jedoch gute Arbeit bei der Implementierung von IDisposable für diese Objekttypen geleistet. Dies wird durch die Tatsache belegt, dass IDisposable implementiert wird. In Bezug auf diese Beweise sollten wir es als verwaltetes Objekt betrachten.
Malik Khalil
12

Nicht verwaltete Ressourcen sind Ressourcen, die außerhalb der .NET-Laufzeit (CLR) (auch bekannt als Nicht-.NET-Code) ausgeführt werden. Beispielsweise ein Aufruf einer DLL in der Win32-API oder ein Aufruf einer in C ++ geschriebenen DLL.

David
quelle
6

Eine "nicht verwaltete Ressource" ist keine Sache, sondern eine Verantwortung. Wenn ein Objekt eine nicht verwaltete Ressource besitzt, bedeutet dies, dass (1) eine Entität außerhalb der Ressource auf eine Weise manipuliert wurde, die Probleme verursachen kann, wenn sie nicht bereinigt wird, und (2) das Objekt über die für die Durchführung einer solchen Bereinigung erforderlichen Informationen verfügt und dafür verantwortlich ist dafür.

Obwohl viele Arten von nicht verwalteten Ressourcen sehr stark mit verschiedenen Arten von Betriebssystementitäten (Dateien, GDI-Handles, zugewiesene Speicherblöcke usw.) verbunden sind, gibt es keinen einzigen Entitätstyp, der von allen gemeinsam genutzt wird, außer der Verantwortung von Aufräumen. Wenn ein Objekt entweder für die Durchführung der Bereinigung verantwortlich ist, verfügt es normalerweise über eine Dispose-Methode, die es anweist, alle Bereinigungen durchzuführen, für die es verantwortlich ist.

In einigen Fällen berücksichtigen Objekte die Möglichkeit, dass sie verlassen werden, ohne dass zuvor jemand Dispose angerufen hat. Mit dem GC können Objekte eine Benachrichtigung anfordern, dass sie abgebrochen wurden (durch Aufrufen einer Routine namens Finalize), und Objekte können diese Benachrichtigung verwenden, um selbst eine Bereinigung durchzuführen.

Begriffe wie "verwaltete Ressource" und "nicht verwaltete Ressource" werden leider von verschiedenen Personen verwendet, um unterschiedliche Bedeutungen zu haben. Ehrlich gesagt ist es sinnvoller, in Bezug auf Objekte zu denken, dass sie entweder keine Bereinigungsverantwortung haben, eine Bereinigungsverantwortung haben, die nur dann erledigt wird, wenn Dispose aufgerufen wird, oder eine Bereinigungsverantwortung haben, die über Dispose erledigt werden sollte, aber kann wird auch von Finalize erledigt.

Superkatze
quelle
5

Der grundlegende Unterschied zwischen einer verwalteten und einer nicht verwalteten Ressource besteht darin, dass der Garbage Collector alle verwalteten Ressourcen kennt. Zu einem bestimmten Zeitpunkt wird der GC den gesamten Speicher und die Ressourcen bereinigen, die einem verwalteten Objekt zugeordnet sind. Der GC kennt nicht verwaltete Ressourcen wie Dateien, Streams und Handles nicht. Wenn Sie sie also nicht explizit in Ihrem Code bereinigen, treten Speicherlecks und gesperrte Ressourcen auf.

Von hier gestohlen , können Sie den gesamten Beitrag lesen.

Marko
quelle
2

Jede Ressource, für die Speicher im verwalteten .NET-Heap zugewiesen ist, ist eine verwaltete Ressource. CLR ist sich dieser Art von Speicher voll bewusst und wird alles tun, um sicherzustellen, dass er nicht verwaist ist. Alles andere wird nicht verwaltet. Wenn Sie beispielsweise mit COM interoperieren, werden möglicherweise Objekte im Prozessspeicherbereich erstellt, CLR kümmert sich jedoch nicht darum. In diesem Fall sollte das verwaltete Objekt, das Anrufe über die verwaltete Grenze tätigt, die Verantwortung für alles darüber hinaus tragen.

Soundararajan
quelle
0

Lassen Sie uns zunächst verstehen, wie VB6- oder C ++ - Programme (Nicht-Dotnet-Anwendungen) ausgeführt wurden. Wir wissen, dass Computer nur Code auf Maschinenebene verstehen. Code auf Maschinenebene wird auch als nativer oder binärer Code bezeichnet. Wenn wir also ein VB6- oder C ++ - Programm ausführen, kompiliert der jeweilige Sprachcompiler den jeweiligen Sprachquellcode in nativen Code, der dann vom zugrunde liegenden Betriebssystem und der zugrunde liegenden Hardware verstanden werden kann.

Der native Code (nicht verwalteter Code) ist spezifisch (nativ) für das Betriebssystem, auf dem er generiert wird. Wenn Sie diesen kompilierten nativen Code verwenden und versuchen, ihn auf einem anderen Betriebssystem auszuführen, schlägt er fehl. Das Problem bei dieser Art der Programmausführung ist also, dass sie nicht von einer Plattform auf eine andere Plattform portierbar ist.

Lassen Sie uns nun verstehen, wie ein .Net-Programm ausgeführt wird. Mit dotnet können wir verschiedene Arten von Anwendungen erstellen. Einige der gängigen Arten von .NET-Anwendungen sind Web-, Windows-, Konsolen- und Mobilanwendungen. Unabhängig vom Typ der Anwendung geschieht Folgendes, wenn Sie eine .NET-Anwendung ausführen

  1. Die .NET-Anwendung wird in Intermediate Language (IL) kompiliert. IL wird auch als Common Intermediate Language (CIL) und Microsoft Intermediate Language (MSIL) bezeichnet. Sowohl .NET- als auch Nicht-.NET-Anwendungen generieren eine Assembly. Baugruppen haben die Erweiterung .DLL oder .EXE. Wenn Sie beispielsweise eine Windows- oder Konsolenanwendung kompilieren, erhalten Sie eine EXE-Datei. Wenn Sie ein Web- oder Klassenbibliotheksprojekt kompilieren, erhalten Sie eine DLL. Der Unterschied zwischen einer .NET- und einer NON .NET-Assembly besteht darin, dass die DOTNET-Assembly im Zwischensprachenformat vorliegt, während die NON DOTNET-Assembly im nativen Codeformat vorliegt.

  2. NICHT-DOTNET-Anwendungen können direkt auf dem Betriebssystem ausgeführt werden, während DOTNET-Anwendungen auf einer virtuellen Umgebung ausgeführt werden, die als Common Language Runtime (CLR) bezeichnet wird. CLR enthält eine Komponente namens Just In-Time Compiler (JIT), die die Intermediate-Sprache in nativen Code konvertiert, den das zugrunde liegende Betriebssystem verstehen kann.

In .NET besteht die Anwendungsausführung aus zwei Schritten: 1. Der Sprachcompiler kompiliert den Quellcode in Intermediate Language (IL). 2. Der JIT-Compiler in CLR konvertiert den IL in nativen Code, der dann auf dem zugrunde liegenden Betriebssystem ausgeführt werden kann .

Da eine .NET-Assembly im Intermedaite Language-Format und nicht in nativem Code vorliegt, können .NET-Assemblys auf jede Plattform portiert werden, sofern die Zielplattform über die Common Language Runtime (CLR) verfügt. Die CLR der Zielplattform konvertiert die Intermedaite-Sprache in nativen Code, den das zugrunde liegende Betriebssystem verstehen kann. Intermediate Languge wird auch als verwalteter Code bezeichnet. Dies liegt daran, dass CLR den darin enthaltenen Code verwaltet. In einem VB6-Programm ist der Entwickler beispielsweise dafür verantwortlich, den von einem Objekt verbrauchten Speicher freizugeben. Wenn ein Programmierer vergisst, Speicher freizugeben, kann es schwierig sein, Ausnahmen für nicht genügend Speicher zu erkennen. Auf der anderen Seite muss sich ein .NET-Programmierer nicht darum kümmern, den von einem Objekt verbrauchten Speicher freizugeben. Die automatische Speicherverwaltung, auch als Grabage Collection bezeichnet, wird von CLR bereitgestellt. Ein Teil, Bei der Speicherbereinigung bietet die CLR mehrere weitere Vorteile, die wir in einer späteren Sitzung erörtern werden. Da CLR die Intermediate Language verwaltet und ausführt, wird sie auch als verwalteter Code bezeichnet.

.NET unterstützt verschiedene Programmiersprachen wie C #, VB, J # und C ++. C #, VB und J # können nur verwalteten Code (IL) generieren, während C ++ sowohl verwalteten Code (IL) als auch nicht verwalteten Code (nativen Code) generieren kann.

Der native Code wird nirgendwo dauerhaft gespeichert. Nachdem wir das Programm geschlossen haben, wird der native Code weggeworfen. Wenn wir das Programm erneut ausführen, wird der native Code erneut generiert.

Das .NET-Programm ähnelt der Ausführung von Java-Programmen. In Java haben wir Bytecodes und JVM (Java Virtual Machine), wo wir wie in .NET Intermediate Language und CLR (Common Language Runtime) verwenden.

Dies wird über diesen Link bereitgestellt - Er ist ein großartiger Tutor. http://csharp-video-tutorials.blogspot.in/2012/07/net-program-execution-part-1.html

himanshupareek66
quelle