2013-06-19 10 views
5

Podejrzewam, że powodem, dla którego ta funkcja nie istnieje, jest to, że jej realizacja jest złożona i niewielu ludzi jej potrzebuje. Aby być bezpiecznym, chcesz, aby przypinanie działało przechodnie, tzn. Chcesz przypiąć cały wykres dostępnych obiektów. Ale nie wydaje się, że czegoś zasadniczo nie da się zrobić.Dlaczego GCHandle.Alloc nie może przypinać obiektów zawierających odniesienia?

przykład, załóżmy, że masz następujące klasy:

[StructLayout(LayoutKind.Sequential)] 
class SomeObject 
{ 
    public SomeObject r; 
} 

które można przydzielić jak:

SomeObject o = new SomeObject(); 

i próby przypiąć go:

GCHandle oh = GCHandle.Alloc(o, GCHandleType.Pinned); 

będziesz złapać strach:

Object contains non-primitive or non-blittable data. 

OK, dobrze, mogę z tym żyć. Ale przypuśćmy, że mam dostęp do implementacji garbage collectora .NET. Jakie byłyby przeszkody? Oto przeszkody, które widzę:

  1. Kołowe odniesienia.
  2. Chcesz, by garbage collecting ograniczył się do obiektów wewnątrz sterty aplikacji.
  3. Może to zająć dużo czasu.
  4. Ciężko/bolesnie uczynić operację atomową.

Wydaje mi się, że GC ma już do czynienia z niektórymi z tych problemów. Co więc zapominam?

UWAGA: Zanim zapytasz "Co chcesz osiągnąć?", Itp., Celem moich pytań jest kod badań, niekoniecznie ograniczony do C# i niekoniecznie ograniczony do CLR. Rozumiem, że manipulowanie pamięcią w środowisku wykonawczym nie jest typowym scenariuszem. W każdym razie nie jest to kwestia czysto spekulatywna.

UWAGA 2: Poza tym nie dbam o marshaling. Po prostu martwię się o przypinanie.

Odpowiedz

9

GC wie tylko, że cokolwiek zrobisz, nie będzie działać. Pamiętasz pamięć o powodzie powód, z pewnością jest uzyskanie stabilnego IntPtr do obiektu. Które następnie następnie, powiedzmy, przejdź do niezarządzanego kodu.

Istnieje jednak problem z zawartości wskazanej pamięci. Zawiera wskaźnik do zarządzanego obiektu. Wskaźnik zmienia się losowo losowo zmienia się, gdy inny wątek przydziela pamięć i uruchamia kolekcję. Które będą spustoszyć każdy kod, który używa przypiętej zawartości pamięci. Nie ma sposobu na uzyskanie stabilnego wskaźnika, nie można "zamrozić" kolektora. Przypinanie wskaźnika również nie działa, po prostu przekazuje klucz do następnego wskazanego obiektu. Mam nadzieję, że prędzej czy później straci ona ważność, ale GC.Alloc nie przejdzie całego wykresu zależności, aby sprawdzić, czy nie ma przyzwoitej górnej granicy czasu, który może zająć. Dozwolone jest przypięcie całego pokolenia, to bardzo trudny impas.

Brzydkie problemy, o wiele łatwiej było to zabronić. Nie ma większego problemu, i tak dzieje się codziennie.

+0

Co by to znaczyło, gdyby zmodyfikować odniesienie wewnątrz przypiętego obiektu? Czy odpiąłby stare referencje i przypiął nowy? Obliczenie przechodniego zamknięcia referencji jest tak kosztowne, jak GC. Teraz chcesz to zrobić w dowolnym momencie zmiany odniesienia w dowolnym miejscu w systemie? –

+0

Ta odpowiedź nie ma sensu. Na początek nic o GC nie jest przypadkowe. Poza kontrolą, tak. Ale to nie ma znaczenia: jeśli przypinam obiekt, mam stabilny wskaźnik do tego obiektu. Teraz znajduję pola tego przypiętego obiektu (również stabilnego), otrzymuję odnośnik do wskazanego obiektu i przypinam go. Nic w tym procesie nie sprawia, że ​​referencje są mniej stabilne, a więc przez indukcję powinienem być w stanie przechylić cały wykres obiektów przechodniowo. Nie chcesz przypinać więcej niż raz, ale to jest szczegół implementacji. CHCĘ przypiąć cały wykres obiektów, dlatego pytam. –

+0

Heja, nie oczekiwałem, że będziesz zadowolony z odpowiedzi. Mówisz, że dobrze to zrobisz, projektanci CLR zwątpili w to, powiedzieli "nie" i to już koniec. Możesz publikować prośby o nowe funkcje w witrynie connect.microsoft.com lub udostępniać ją w Mono. –

Powiązane problemy