Der GC kann Referenzen verschieben. Die Verwendung von unsicher hält ein Objekt außerhalb der Kontrolle des GC und vermeidet dies. "Behoben" fixiert ein Objekt, lässt aber den GC den Speicher verwalten.
Wenn Sie per Definition einen Zeiger auf die Adresse eines Objekts haben und der GC ihn verschiebt, ist Ihr Zeiger nicht mehr gültig.
Warum Sie Zeiger benötigen: Der Hauptgrund ist die Arbeit mit nicht verwalteten DLLs, z. B. solchen, die in C ++ geschrieben wurden
Beachten Sie außerdem, dass Sie anfälliger für Heap-Fragmentierung sind, wenn Sie Variablen anheften und Zeiger verwenden.
Bearbeiten
Sie haben das Kernproblem von verwaltetem und nicht verwaltetem Code angesprochen ... Wie wird der Speicher freigegeben?
Sie können Code für die Leistung mischen, wie Sie es beschreiben. Sie können verwaltete / nicht verwaltete Grenzen einfach nicht mit Zeigern überschreiten (dh Sie können keine Zeiger außerhalb des "unsicheren" Kontexts verwenden).
Wie sie gereinigt werden ... Sie müssen Ihr eigenes Gedächtnis verwalten; Objekte, auf die Ihre Zeiger zeigen, wurden mithilfe von (hoffentlich) erstellt / zugewiesen (normalerweise innerhalb der C ++ - DLL) CoTaskMemAlloc()
, und Sie müssen diesen Speicher auf dieselbe Weise freigeben, indem CoTaskMemFree()
Sie aufrufen , oder es kommt zu einem Speicherverlust. Beachten Sie, dass nur mit zugewiesener Speicher CoTaskMemAlloc()
freigegeben werden kann CoTaskMemFree()
.
Die andere Alternative besteht darin, eine Methode aus Ihrer nativen C ++ - DLL verfügbar zu machen, die einen Zeiger verwendet und freigibt. Auf diese Weise kann die DLL entscheiden, wie der Speicher freigegeben werden soll. Dies funktioniert am besten, wenn eine andere Methode zum Zuweisen von Speicher verwendet wird. Die meisten nativen DLLs, mit denen Sie arbeiten, sind DLLs von Drittanbietern, die Sie nicht ändern können, und sie haben normalerweise keine (wie ich gesehen habe) Funktionen zum Aufrufen.
Ein Beispiel für die Speicherfreigabe von hier :
string[] array = new string[2];
array[0] = "hello";
array[1] = "world";
IntPtr ptr = test(array);
string result = Marshal.PtrToStringAuto(ptr);
Marshal.FreeCoTaskMem(ptr);
System.Console.WriteLine(result);
Noch etwas Lesematerial:
C # Freigabe des von IntPtr referenzierten Speichers
In der zweiten Antwort werden die verschiedenen Zuordnungs- / Freigabemethoden erläutert
Wie kann ich IntPtr in C # freigeben?
Verstärkt die Notwendigkeit, die Zuordnung auf dieselbe Weise aufzuheben, wie der Speicher zugewiesen wurde
http://msdn.microsoft.com/en-us/library/aa366533%28VS.85%29.aspx
Offizielle MSDN-Dokumentation zu den verschiedenen Möglichkeiten zum Zuweisen und Freigeben von Speicher.
Kurz gesagt ... Sie müssen wissen, wie der Speicher zugewiesen wurde, um ihn freizugeben.
Bearbeiten
Wenn ich Ihre Frage richtig verstehe, lautet die kurze Antwort Ja. Sie können die Daten an nicht verwaltete Zeiger übergeben, in einem unsicheren Kontext damit arbeiten und die Daten verfügbar haben, sobald Sie den unsicheren Kontext verlassen.
Der Schlüssel ist, dass Sie das verwaltete Objekt, auf das Sie verweisen, mit einem fixed
Block verbinden müssen. Dies verhindert, dass der Speicher, auf den Sie verweisen, vom GC im unsafe
Block verschoben wird . Hier gibt es eine Reihe von Feinheiten, z. B. können Sie einen in einem festen Block initialisierten Zeiger nicht neu zuweisen. Sie sollten sich über unsichere und feste Anweisungen informieren, wenn Sie wirklich Ihren eigenen Code verwalten möchten.
Die Vorteile der Verwaltung Ihrer eigenen Objekte und der Verwendung von Zeigern in der von Ihnen beschriebenen Weise führen jedoch möglicherweise nicht zu einer Leistungssteigerung, wie Sie vielleicht denken. Gründe warum nicht:
- C # ist sehr optimiert und sehr schnell
- Ihr Zeigercode wird weiterhin als IL generiert, das angepasst werden muss (an diesem Punkt kommen weitere Optimierungen ins Spiel).
- Sie schalten den Garbage Collector nicht aus ... Sie halten nur die Objekte, mit denen Sie arbeiten, aus dem Zuständigkeitsbereich des GC heraus. Also alle 100 ms oder so, die GC noch unterbricht Ihren Code und führt seine Funktionen für alle anderen Variablen in Ihrem verwalteten Code.
HTH,
James