2011-07-04 16 views
5

Możliwe duplikaty:
Is it possible to have a memory leak in managed code? (specifically C# 3.0)
Memory Leak in C#Jak stworzyć wyciek pamięci w C#/.NET

Było podobne pytanie o tym wczoraj, ale dla Java, więc jest zainteresowany - co trzeba zrobić, aby utworzyć przeciek pamięci w C#/.NET (bez użycia niebezpiecznych)?

+1

Niektóre odpowiedzi w tym wątku są polityczne, na prawdziwy przykład patrz tutaj: http://smartbear.com/support/articles/aqtime/net-allocation-profiler/ - "Oczywiście ten handler nie jest usuwany z danego zdarzenia, co skutkuje przeciekiem." –

Odpowiedz

12

zdarzenia statyczne; ŚMIESZNIE, ponieważ nigdy nie wykraczają poza zakres.

static event EventHandler Evil; 

for(int i = 0 ; i < 1000000 ; i++) 
    Evil += delegate {}; 

Sposób anonimowy jest po prostu ładny-to-mieć tutaj, ale są ładne, ponieważ również to świnia zrezygnować, jeśli nie brać pod kopię zmiennej/pola i zapisz że.

Technicznie nie jest to faktycznie „wyciekły”, ponieważ nadal można uzyskać do nich dostęp poprzez Evil.GetInvocationList() - jednak w przypadku korzystania z regularnych obiektów może spowodować nieoczekiwane wcieleń obiektów, tj

MyHeavyObject obj = ... 
... 
SomeType.SomeStaticEvent += obj.SomeMethod; 

obecnie przedmiotem na obj żyje na zawsze. To satysfakcjonujące odczucie postrzeganego przecieku IMO i "moja aplikacja umarła okropną śmiercią" jest wystarczająco dobre dla mnie; p

+0

, ale nadal możesz się do nich dostać ... nie? –

+1

Tak, musiałem naprawić to * raz * przed ... dokładnie raz, ponieważ to się nie powtórzy =) –

+0

@Adam Ralph: Wszyscy subskrybenci będą przechowywani w nieskończoność (chyba że są niezarejestrowani z wydarzenia), ponieważ wydarzenie jest statyczne. –

5

Gdy obiekt subskrybuje zdarzenie, obiekt wystawiający zdarzenie utrzymuje odniesienie do subskrybenta (w rzeczywistości zdarzenie, MultiCastDelegate pierwotnie robi, ale przechodzi przez). To odniesienie uniemożliwi subskrybowanie subskrybenta, jeśli ostatnie odniesienie do niego (inne niż to, które jest utrzymywane przez event) wykracza poza zakres.

Pozostałe dwie odpowiedzi mają tę sytuację całkowicie wstecz i są niepoprawne. Jest to trochę trudne do pokazania w prostym przykładzie i jest zwykle widoczne w większych projektach, ale pamiętaj, że odniesienie do subskrybenta jest utrzymywane przez MultiCastDelegate (event) i powinieneś być w stanie to przemyśleć.

EDIT: Jak Marc wspomina w swojej odpowiedzi można technicznie uzyskać odniesienie do „wycieku” obiektu metodą GetInvocationList(), ale kod jest mało prawdopodobne, aby przy użyciu tego i to nie będzie miało znaczenia, kiedy awaria ze związkiem OutOfMemoryExcetion .

+0

bardzo prawdziwe i całkowicie się zgadzam - ale powinniśmy pamiętać, że to nie odpowiada na pytanie –

+0

@Adam Ralph: Nie ma? Opisuje jeden sposób wycieku pamięci. Jak to uniknąć odpowiedzi na pytanie? –

+0

Nie zgadzam się, że opisujesz wyciek pamięci.Przeciek pamięci oznacza, że ​​GC jest zepsuty, ponieważ nie zwalnia całej pamięci używanej przez nieusunięte obiekty. W opisywanej sytuacji odniesienia i czasy życia są utrzymywane poprawnie, a GC utrzymuje wszystkie obiekty przy życiu, które powinien. –

1

Bezpośredni dostęp do pamięci jest pobierany z bezpiecznego kodu zarządzanego. Musi być gdzieś połączenie z niebezpiecznym kodem, aby wywołać wyciek pamięci, albo w kodzie, który piszesz, albo w zasobie strony trzeciej (prawdopodobnie w FCL) z błędem wycieku pamięci.