Garbage Collector, część V– destruktory, wydajność, przykład

W ostatnim poście obiecałem pokazać na przykładzie, że destruktory rzeczywiście mają negatywny wpływ na wydajność. Mamy prostą klasę:

class MyClass
{
    ~ MyClass()
    {
        // Jakis bezensowny kod np:
        for (int i = 0; i <  100; i++){}
    }
}

Następnie stwórzmy kilkaset obiektów:

Stopwatch stopwatch=new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 100 * 10000; i++)
{
    var newInstance = new MyClass();
}
stopwatch.Stop();
long duration = stopwatch.ElapsedMilliseconds;

Przyjrzyjmy się teraz diagramowi przedstawiającemu rozkład obiektów względem generacji (CLR Profiler):

image

Na moim komputerze duration wyniósł 900. Usuńmy destruktor i dokonajmy analogicznej obserwacji:

image

Czas deklaracji wyniósł 450. Jakie wnioski? Oczywiście użycie destruktorów spowodowało wypromowanie zwalnianych obiektów do drugiej generacji. Proporcje GEN0 do GEN1 niemal są odwrotne – bez destruktora większość obiektów zawalnianych jest w GEN0.  Ponadto sama inicjalizacja (wykonanie pętli) zabrała 2x więcej czasu. Rozwiązaniem jest użycie interfejsu IDisposable.

3 thoughts on “Garbage Collector, część V– destruktory, wydajność, przykład”

  1. Piszesz że interfejs IDisposable jest leszy niż destruktor pod względem wydajności i jednocześnie linkujesz do posta w którym opisujesz jego prawidłową implementację, która polega m.in. na napisaniu destruktora, więc trochę Cię nie rozumiem. Sugerujesz żeby implementując IDisposable nie pisać destruktora? Czy może rozwiązanie IDisposable + destruktor jest wydajniejsze niż rozwiązanie z samym tylko destruktorem?

  2. @Marcin:
    Dobra uwaga. Proszę jednak zauważyć, że w Dispose wywołujemy GC.SupressFinalize(this)- czyli jeśli użytkownik użyje Dispose wtedy destruktor nie będzie wędrował do freachable queue.

  3. Hej.

    Mam małe pytanko odnośnie tego i załączonego wpisu, mianowicie:

    IDisposable ratuje nas tylko wtedy gdy rzeczywiście go użyjemy prawda? Jeżeli GC sam wywoła nas destruktor to nastąpi w/w problem i nic na to nie poradzimy. Taki urok destruktorów.

    Co to są zasoby zarządzalne a niezarządzalne i dlatego GC ma usuwać tylko te drugie? W C# nie ma chyba żadnej metody typu “free”. Jakoś nie mogę sobie tego wyobrazić.

Leave a Reply

Your email address will not be published.