2010-11-11 8 views
6

Angenommen, Sie haben eine verwaltete Klasse, die ein Delegatenmitglied in einen nativen Funktionszeiger konvertiert und an den systemeigenen Code übergibt. Angenommen, die Klasse/der Delegat bleibt im Gültigkeitsbereich und ändert sich nicht für die Lebensdauer des systemeigenen Codes (so dass er vom GC nicht offensichtlich zerstört wird). Welche anderen Probleme sollte man in dieser Situation beachten? Ist es beispielsweise möglich, dass der GC den Delegaten oder die tatsächliche Methode, auf die der Delegat verweist, verschiebt und den systemeigenen Code mit einer Zugriffsverletzung verlässt?Gefahren beim Konvertieren von Delegaten in Funktionszeiger

+0

"Aufenthalte in Geltungsbereich" ist mit den anderen Behauptungen in Ihrer Frage nicht sinnvoll . –

Antwort

2

Es scheint, dass es möglich ist, den Speicherort der Delegate/Funktion zu pinnen, aber dies behindert einen großen Vorteil der .NET GC: Komprimierung.

Sobald ein GC-Sweep durchgeführt wurde, wird jedes Objekt im Speicher verschoben, um zusammenhängend zu sein. Dies macht den Zugriff und die Zuweisung schneller, als wenn der Heap fragmentiert wäre. Wenn Sie ein Objekt im Heap anordnen müssen, müsste der GC es umgehen und wenn es mehrere Male durchgeführt würde, könnte dies zu einer nicht-trivialen Heap-Fragmentierung führen. (Übrigens wird dies mit GCHandle in dem von Ron Warholic verlinkten Artikel angesprochen. Ich bin mir nicht sicher, ob das außerhalb von verwaltetem C++ verfügbar ist.)

2

Ich bin nicht viel von einem .Net-Experten, aber ich denke, Sie sollten einen Blick hier werfen: Marshal Callbacks and Delegates Using C++ Interop.

bemerken, dass es möglich ist, aber nicht notwendig, die Delegierten Verwendung pin_ptr festzustecken, damit er nicht Wieder angeordnet ist oder der von der garbage collector angeordnet ist. Schutz vor vorzeitige Garbage Collection ist erforderlich, aber Pinning bietet mehr Schutz als erforderlich ist, wie es verhindert Sammlung verhindert aber auch verhindert Verlagerung.

+0

Das folgende Beispiel ähnelt dem vorherigen Beispiel, aber in diesem Fall wird der bereitgestellte Funktionszeiger von der nicht verwalteten API gespeichert, sodass er jederzeit aufgerufen werden kann, sodass die Speicherbereinigung für eine beliebige Zeitspanne unterdrückt werden muss. Daher wird im folgenden Beispiel eine globale Instanz von GCHandle verwendet, um zu verhindern, dass der Delegat unabhängig vom Funktionsumfang verschoben wird. Wie im ersten Beispiel besprochen, ist die Verwendung von pin_ptr für diese Beispiele nicht notwendig, würde aber in diesem Fall sowieso nicht funktionieren, da der Umfang eines pin_ptr auf eine einzige Funktion beschränkt ist. – NoSenseEtAl

2

Der GC kann den Delegaten verschieben, aber nicht den systemeigenen Code, den der Delegat eingibt. Solange der Delegat nicht erfasst wird, bleibt der Funktionszeiger gültig.

Beachten Sie, dass "im Geltungsbereich" nicht ausreicht, um die Erfassung eines Objekts zu verhindern. Es muss verwendet werden (möglicherweise durch einen Anruf an GC.KeepAlive).

+0

Nicht sicher, ich folge, der Delegat umschließt eine verwaltete Methode, die von systemeigenem Code aufgerufen wird, aber +1 für das "muss verwendet werden" – insipid

2

Eine schnelle Suche zeigt einige Microsoft guidance zu dem Problem. Der Artikel ist für verwaltetes C++ gedacht, aber die Anleitung sollte für jede Sprache in der CLR gelten.

Die Idee ist, dass Sie verhindern müssen, dass der Delegat selbst verschoben oder entsorgt wird, aber (natürlich) kann der zugrunde liegende Code nicht verschoben werden. Sobald der JIT in nativen Code kompiliert wurde, ist dieser Code behoben und sollte sich nicht bewegen.

Verwandte Themen