2011-05-06 13 views
14

Chciałbym sprawdzić, czy kod konfigurujący WeakReference nie zawiera przypadkowo silnego odniesienia do obiektu, do którego się odwołuje. (Oto an example, jak łatwo jest to zrobić przypadkowo.)Testowanie/weryfikacja słabej referencji

Czy to wygląda na najlepszy sposób na sprawdzenie niezamierzonych silnych odniesień?

TestObject testObj = new TestObject(); 
WeakReference wr = new WeakReference(testObj); 

// Verify that the WeakReference actually points to the intended object instance. 
Assert.Equals(wr.Target, testObject); 

// Force disposal of testObj; 
testObj = null; 
GC.Collect(); 
// If no strong references are left to the wr.Target, wr.IsAlive will return false. 
Assert.False(wr.IsAlive); 
+0

Nie można oczekiwać GC.Collect(), aby wymusić GC do zbierania śmieci, to tylko sugestia, więc nie może usunąć obiekt. [Automatyczne gromadzenie pamięci w .Net] (http://msdn.microsoft.com/en-us/library/f144e03t.aspx) –

+0

Czy mógłbyś zastanowić się, dlaczego GC.Collect() może nie zniszczyć obiektu, który kwalifikuje się do kolekcja? –

+0

Apparantly wymusza w trybie domyślnym. Dopiero wtedy, gdy jest ustawiony w trybie zoptymalizowanym, tak się nie stało, nie zdawałem sobie z tego sprawy. –

Odpowiedz

11

Dostałem w kontakcie z firmą Microsoft o tym i dowiedziałem/potwierdziły, że:

  • GC.Collect() wymusza blokowania zbierania śmieci .
  • Po uruchomieniu GC.Collect() nie będzie w tajemniczy sposób pomijać obiektów kwalifikujących się do kolekcji. Przewidywane reguły są stosowane w celu określenia, które obiekty mają zostać zebrane. Tak długo jak działasz z zrozumieniem tych reguł (tj. Jak obsługiwane są obiekty finalizowane), możesz wymusić zniszczenie określonego obiektu, chociaż pamięć używana przez zniszczony obiekt może zostać zwolniona lub nie.

Więcej informacji na moim blogu: Can .Net garbage collection be forced?

4

Zrobiłem to dopiero wczoraj. Oto, co musiałem dodać, aby zapewnić gromadzenie się przed ostatnim assert:

 GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     GC.WaitForFullGCComplete(); 
     GC.Collect(); 

Jeśli po tym .IsAlive nadal jest prawdziwa, to prawdopodobnie nadal istnieje silna odniesienie gdzieś.

Nawiasem mówiąc - NIE WOLNO sprawdzać .IsAlive po uzyskaniu dostępu do celu WeakReference. Aby uniknąć sytuacji wyścigu między wami sprawdzanie .IsAlive i .Target, to zrobić:

var r = weakRef.Target AS Something; 
if (r != null) 
{ 
    ... do your thing 
} 
+0

Kod nie * zapewnia *, że obiekt jest gromadzony, nie można wymusić w ten sposób GC. Nadal możesz używać 'IsAlive', jeśli wykonujesz podwójną kontrolę, tzn. Sprawdzasz także wartość zerową po uzyskaniu celu. Może to być przydatne, jeśli chcesz, aby czek pomijał wcześnie, bez konieczności wykonywania rzucania, jeśli masz pewność, że nie ma nic do rzucenia. – Guffa

+3

GC.Collect() preforms kolekcja blokowania - metoda zwraca tylko po zakończeniu kolekcji, więc wywołanie GC.WaitForFullGCComplete() powinny być niepotrzebne. GC.WaitForFullGCComplete() jest przeznaczony do użycia w innym scenariuszu. –

Powiązane problemy