Jak pozbyć się klasy in.net?

. NET garbage collector w końcu zwolni pamięć, ale co, jeśli chcesz natychmiast odzyskać tę pamięć? Jaki kod należy użyć w klasie MyClass, aby wywołać

MyClass.Dispose()

I zwolnić całą używaną przestrzeń przez zmienne i obiekty w MyClass?

Author: Jon Galloway, 2008-08-15

20 answers

IDisposable nie ma nic wspólnego z uwalnianiem pamięci. IDisposable to wzorzec uwalniania niezarządzanych zasobów - a pamięć jest zdecydowanie zarządzanym zasobem.

Linki wskazujące na GC.Collect() jest poprawną odpowiedzią, chociaż korzystanie z tej funkcji jest generalnie zniechęcane przez dokumentację Microsoft.NET.

Edit: zarobiwszy pokaźną ilość karmy za tę odpowiedź, czuję pewną odpowiedzialność, aby rozwinąć ją, aby nie Przybysz do zarządzania zasobami. NET uzyskać złe wrażenie.

Wewnątrz procesu. NET istnieją dwa rodzaje zasobów-zarządzany i niezarządzany. "Zarządzane" oznacza, że runtime kontroluje zasób, podczas gdy "niezarządzane" oznacza, że to odpowiedzialność programisty. I tak naprawdę jest tylko jeden rodzaj zarządzanego zasobu, na którym zależy nam dzisiaj w. NET-pamięć. Programista każe runtime przydzielić pamięć, a następnie do runtime należy ustalenie, kiedy pamięć can freed. Mechanizm, który. NET używa do tego celu nazywa się garbage collection i można znaleźć wiele informacji o GC w Internecie po prostu za pomocą Google.

W przypadku innych rodzajów zasobów,. NET nie wie nic o ich czyszczeniu, więc musi polegać na programistach, którzy postąpią właściwie. W tym celu platforma daje programiście trzy narzędzia:

  1. interfejs IDisposable i instrukcja "using" w VB i C #
  2. Finalizery
  3. IDisposable wzorzec zaimplementowany przez wiele klas BCL

Pierwsza z nich pozwala programiście efektywnie pozyskać zasób, użyć go, a następnie zwolnić go w ramach tej samej metody.

using (DisposableObject tmp = DisposableObject.AcquireResource()) {
    // Do something with tmp
}
// At this point, tmp.Dispose() will automatically have been called
// BUT, tmp may still a perfectly valid object that still takes up memory

Jeśli "AcquireResource" jest fabryczną metodą, która (na przykład) otwiera plik i "Dispose" automatycznie zamyka plik, to kod ten nie może wyciekać zasobu pliku. Ale pamięć dla samego obiektu "tmp" może nadal być / align = "left" / To dlatego, że IDisposable interfejs nie ma absolutnie żadnego połączenia z garbage collector. Jeśli Czy chcesz upewnić się, że pamięć została uwolniona, jedyną opcją będzie wywołanie GC.Collect(), Aby wymusić pobieranie śmieci.

Nie można jednak na tyle podkreślić, że prawdopodobnie nie jest to dobry pomysł. Generalnie znacznie lepiej jest pozwolić garbage collector robić to, do czego został zaprojektowany, czyli zarządzać pamięcią.

Co się stanie, jeśli zasób jest używany przez dłuższy okres czasu, tak że jego żywotność przekracza kilka metod? Oczywiście, Instrukcja" using "nie ma już zastosowania, więc programista musiałby ręcznie wywołać" Dispose", gdy skończy z zasobem. A co się stanie, jeśli programista zapomni? Jeśli nie ma alternatywy, proces lub komputer może w końcu zabraknąć zasobu, który nie jest prawidłowo zwolniony.

To miejsce, w którym pojawiają się finalizery. Finalizer to metoda na twojej klasie, która ma szczególny związek ze śmieciarzem. GC obiecuje , że-przed uwolnieniem pamięci dla dowolnego obiektu tego typu-najpierw da finalizatorowi szansę na jakieś oczyszczenie.

Więc w przypadku pliku, teoretycznie nie musimy w ogóle zamykać pliku ręcznie. Możemy poczekać, aż dotrze do niego Śmieciarz, a potem pozwolić finalizatorowi wykonać robotę. Niestety nie działa to dobrze w praktyce, ponieważ garbage collector działa niedeterministycznie. Plik może pozostać otwarty znacznie dłużej, niż oczekuje programista. A jeśli wystarczająca liczba plików jest otwarta, system może się nie udać podczas próby otwarcia dodatkowego pliku.

Dla większości zasobów, chcemy obu tych rzeczy. Chcemy, aby konwencja mogła powiedzieć "skończyliśmy z tym zasobem teraz" i chcemy mieć pewność, że istnieje przynajmniej pewna szansa na automatyczne czyszczenie, jeśli zapomnimy zrobić to ręcznie. Tam " IDisposable" wzór wchodzi w grę. Jest to konwencja, która pozwala IDispose i finalizer grać ładnie razem. Możesz zobaczyć, jak działa wzór, przeglądając oficjalną dokumentację Dla IDisposable.

Podsumowując: jeśli naprawdę chcesz się upewnić, że pamięć jest wolna, to IDisposable i finalizery Ci nie pomogą. Ale IDisposable interfejs jest częścią niezwykle ważnego wzorca, który wszyscy programiści. NET powinni zrozumieć.

 100
Author: Curt Hagenlocher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-02 01:44:45

Można usuwać tylko instancje, które implementują IDisposable interface.

Aby wymusić natychmiastowe zwolnienie (niezarządzanej) pamięci:

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

Jest to zwykle zła praktyka, ale istnieje na przykład błąd w wersji x64. NET framework, który sprawia, że GC zachowuje się dziwnie w niektórych scenariuszach, a następnie możesz chcieć to zrobić. Nie wiem, czy błąd został już rozwiązany. Czy ktoś wie?

Aby pozbyć się klasy, którą wykonujesz to:

instance.Dispose();

Lub tak:

using(MyClass instance = new MyClass())
{
    // Your cool code.
}

, które zostaną przetłumaczone w czasie kompilacji na:

MyClass instance = null;    

try
{
    instance = new MyClass();        
    // Your cool code.
}
finally
{
    if(instance != null)
        instance.Dispose();
}

Możesz zaimplementować interfejs IDisposable w następujący sposób:

public class MyClass : IDisposable
{
    private bool disposed;

    /// <summary>
    /// Construction
    /// </summary>
    public MyClass()
    {
    }

    /// <summary>
    /// Destructor
    /// </summary>
    ~MyClass()
    {
        this.Dispose(false);
    }

    /// <summary>
    /// The dispose method that implements IDisposable.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// The virtual dispose method that allows
    /// classes inherithed from this one to dispose their resources.
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources here.
            }

            // Dispose unmanaged resources here.
        }

        disposed = true;
    }
}
 22
Author: Patrik Svensson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-26 09:31:11

Odpowiedzi na to pytanie trochę się pogubiły.

Tytuł pyta o usuwanie, ale potem mówi, że chcą natychmiast odzyskać pamięć.

. Net jest zarządzany , co oznacza, że pisząc Aplikacje.Net nie musisz martwić się bezpośrednio o pamięć, koszt jest taki, że nie masz bezpośredniej kontroli nad pamięcią.

. Net decyduje, kiedy najlepiej wyczyścić i zwolnić pamięć, nie Ty jako koder. Net.

Dispose jest sposób powiedzieć. Net, że już z czymś skończyłeś, ale to nie zwolni pamięci, dopóki nie będzie to najlepszy czas, aby to zrobić.

Zasadniczo. Net rzeczywiście zbierze pamięć z powrotem, kiedy jest to dla niego najłatwiejsze - jest bardzo dobre w podejmowaniu decyzji, kiedy. Jeśli nie piszesz czegoś bardzo intensywnego w pamięci, zwykle nie musisz tego odrzucać (jest to częściowo powód, dla którego gry nie są jeszcze często pisane w. Net - wymagają pełnej kontroli)

W. Net możesz użyć GC.Collect() do zmusić go do natychmiastowego, ale to jest prawie zawsze zła praktyka. Jeśli. Net jeszcze go nie wyczyścił, oznacza to, że nie jest to szczególnie dobry czas na to.

GC.Collect() pobiera obiekty, które. Net identyfikuje jako zrobione. Jeśli nie usuniesz obiektu, który go potrzebuje. Net może zdecydować o zachowaniu tego obiektu. Oznacza to, że GC.Collect() jest skuteczne tylko wtedy, gdy poprawnie zaimplementujesz swoje jednorazowe instancje.

GC.Collect() jest Nie zamiennikiem poprawnego używania To możliwe.

Więc Dispose i pamięć nie są bezpośrednio powiązane, ale nie muszą być. Poprawne usuwanie sprawi, że Twoje aplikacje. Net będą bardziej wydajne i dlatego zużywają mniej pamięci.


[[10]} 99% czasu w. Net to najlepsza praktyka:

Reguła 1: Jeśli nie zajmujesz się niczym niezarządzanym lub tym, co implementuje IDisposable, nie martw się o pozbycie się.

Reguła 2: Jeśli masz zmienną lokalną, która implementuje IDisposable upewnij się, że pozbędziesz się go w bieżącym zakresie:

//using is best practice
using( SqlConnection con = new SqlConnection("my con str" ) )
{
    //do stuff
} 

//this is what 'using' actually compiles to:
SqlConnection con = new SqlConnection("my con str" ) ;
try
{
    //do stuff
}
finally
{
    con.Dispose();
}

Reguła 3: jeśli klasa ma właściwość lub zmienną składową, która implementuje IDisposable, to ta klasa powinna również implementować IDisposable. W metodzie Disposable tej klasy Możesz również pozbyć się swoich właściwości IDisposable:

//rather basic example
public sealed MyClass :
   IDisposable
{   
    //this connection is disposable
    public SqlConnection MyConnection { get; set; }

    //make sure this gets rid of it too
    public Dispose() 
    {
        //if we still have a connection dispose it
        if( MyConnection != null )
            MyConnection.Dispose();

        //note that the connection might have already been disposed
        //always write disposals so that they can be called again
    }
}

To nie jest naprawdę kompletne, dlatego przykład jest zapieczętowany. Dziedziczenie klas może wymagać przestrzegania następnej reguły...

Reguła 4: Jeśli Klasa używa zasobu niezarządzanego , następnie implementuje IDispose i dodaje finalizer.

. Net nie może nic zrobić z niezarządzanym zasobem, więc teraz mówimy o pamięci. Jeśli tego nie wyczyścisz, możesz mieć wyciek pamięci.

Metoda Dispose musi dotyczyć zarówno zarządzanych, jak i niezarządzanych zasobów.

Finalizer jest bezpiecznym chwytem-zapewnia, że jeśli ktoś inny stworzy i uruchomi Twoją klasę i zawiedzie aby go pozbyć, "niebezpieczne" niezarządzane zasoby mogą być nadal czyszczone przez .Net.

~MyClass()
{
    //calls a protected method 
    //the false tells this method
    //not to bother with managed
    //resources
    this.Dispose(false);
}

public void Dispose()
{
    //calls the same method
    //passed true to tell it to
    //clean up managed and unmanaged 
    this.Dispose(true);

    //as dispose has been correctly
    //called we don't need the 

    //'backup' finaliser
    GC.SuppressFinalize(this);
}

Wreszcie to przeciążenie Dispose, które zabiera flagę boolean:

protected virtual void Dispose(bool disposing)
{
    //check this hasn't been called already
    //remember that Dispose can be called again
    if (!disposed)
    {
        //this is passed true in the regular Dispose
        if (disposing)
        {
            // Dispose managed resources here.
        }

        //both regular Dispose and the finaliser
        //will hit this code
        // Dispose unmanaged resources here.
    }

    disposed = true;
}

Zauważ, że gdy już to wszystko jest na swoim miejscu, inny zarządzany kod tworzący instancję twojej klasy może traktować go jak każdy inny IDisposable(reguły 2 i 3).

 18
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-01 09:09:20

Czy wypadałoby też wspomnieć, że dispose nie zawsze odnosi się do pamięci? Ja pozbywam się zasobów takich odwołań do plików częściej niż pamięci. GC.Collect() odnosi się bezpośrednio do CLR garbage collector i może, ale nie musi, zwolnić pamięć (w Menedżerze Zadań). Prawdopodobnie wpłynie to negatywnie na Twoją aplikację (np. wydajność).

Na koniec dnia dlaczego chcesz natychmiast odzyskać pamięć? Jeśli jest ciśnienie pamięci z innego miejsca, System operacyjny dostanie pamięć w większość przypadków.

 14
Author: Brian Lyttle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-15 15:41:02

Spójrz na ten Artykuł

Implementacja wzorca utylizacji, IDisposable i / lub finalizera nie ma absolutnie nic wspólnego z odzyskiwaniem pamięci; zamiast tego ma wszystko wspólnego z informowaniem GC Jak aby odzyskać to wspomnienie. Wywołanie Dispose() w żaden sposób nie wchodzi w interakcję z GC.

GC uruchomi się tylko wtedy, gdy określi potrzebę (tzw. ciśnienie pamięci) i wtedy (i tylko wtedy) dealokuje pamięć dla nieużywane obiekty i kompaktowa przestrzeń pamięci.

Możesz zadzwonić do GC.Collect (), ale naprawdę nie powinieneś, chyba że istnieje bardzo dobry powód (który prawie zawsze jest "nigdy"). Kiedy wymuszasz taki cykl zbierania poza pasmem, w rzeczywistości sprawiasz, że GC wykonuje więcej pracy i ostatecznie może negatywnie wpłynąć na wydajność aplikacji. Na czas trwania cyklu zbierania GC aplikacja jest rzeczywiście w stanie zamrożonym...im więcej cykli GC, tym więcej czas, jaki Twoja aplikacja spędza na zamrożeniu.

Istnieje również kilka natywnych wywołań API Win32, które możesz wykonać, aby uwolnić swój działający zestaw, ale nawet tych należy unikać, chyba że istnieje bardzo dobry powód, aby to zrobić.

Cała przesłanka za gargbage collected runtime polega na tym, że nie musisz się martwić (tak bardzo) o to, kiedy runtime przydziela/deallokuje rzeczywistą pamięć; musisz się tylko martwić o upewnienie się, że Twój obiekt wie, jak oczyścić po sobie, gdy zostanie zapytany.

 6
Author: Scott Dorman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-24 09:53:31
public class MyClass : IDisposable
{
    public void Dispose()
    {
       // cleanup here
    }
}

Wtedy możesz zrobić coś takiego

MyClass todispose = new MyClass();
todispose.Dispose(); // instance is disposed right here

Lub

using (MyClass instance = new MyClass())
{

}
// instance will be disposed right here as it goes out of scope
 3
Author: Darren Kopp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-15 15:32:02

Complete explanation by Joe Duffy on " Dispose, Finalization, and Resource Management":

Wcześniej w. NET Framework ' s dożywotnio, finalizatorzy byli konsekwentnie określane jako destruktory przez C# programistów. Gdy stajemy się mądrzejsi czas, staramy się pogodzić z tym, że metoda jest bardziej odpowiednikiem C++ Destruktor (deterministyczny) , podczas gdy finalizer to coś zupełnie oddzielne (nieeterministyczny) . Fakt że C# pożyczył Destruktor C++ składnia (tzn. ~T ()) na pewno miała przynajmniej trochę wspólnego z rozwojem ten błąd.

 3
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-26 09:36:18

Napisałem podsumowanie destruktorów i utylizacji i zbiórki śmieci na http://codingcraftsman.wordpress.com/2012/04/25/to-dispose-or-not-to-dispose/

Aby odpowiedzieć na pierwotne pytanie:

  1. nie próbuj zarządzać swoją pamięcią
  2. Dispose nie polega na zarządzaniu pamięcią, lecz na niezarządzanym zarządzaniu zasobami.]}
  3. Finalizery są wrodzoną częścią wzorca utylizacji i faktycznie spowalniają uwalnianie pamięci zarządzanych obiektów (ponieważ muszą wejść w Kolejka Finalizacyjna chyba, że już usunie d)
  4. GC.Zbieranie jest złe, ponieważ sprawia, że niektóre krótkotrwałe przedmioty wydają się być potrzebne na dłużej, a więc spowalnia ich zbieranie.

Jednak GC.Funkcja Collect może być przydatna, jeśli posiadasz sekcję kodu o znaczeniu krytycznym dla wydajności i chcesz zmniejszyć prawdopodobieństwo spowolnienia zbierania śmieci. Nazywałeś to wcześniej.

Na dodatek, jest argument za tym wzór:

var myBigObject = new MyBigObject(1);
// something happens
myBigObject = new MyBigObject(2);
// at the above line, there are temporarily two big objects in memory and neither can be collected

Vs

myBigObject = null; // so it could now be collected
myBigObject = new MyBigObject(2);

Ale główną odpowiedzią jest to, że wywóz śmieci po prostu działa, chyba że bałagan z nim!

 3
Author: Ashley Frieze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-02 22:13:37

Tak naprawdę nie można wymusić na GC czyszczenia obiektu, kiedy chcesz, chociaż istnieją sposoby, aby zmusić go do uruchomienia, nic nie mówi, że to czyści wszystkie obiekty, które chcesz / oczekujesz. Najlepiej nazwać dispose in a try catch ex finally dispose end try (VB.NET rulz) sposób. Ale Dispose służy do czyszczenia zasobów systemowych (pamięci, uchwytów, połączeń db itp. przydzielane przez obiekt w sposób deterministyczny. Dispose nie czyści (i nie może) pamięci używanej przez sam obiekt, tylko GC może to zrobić to.

 2
Author: Booji Boy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-15 15:42:36

Ten artykuł ma dość prostą instrukcję. Jednakże, posiadanie do wywołania GC zamiast pozwolić mu na jego naturalny przebieg jest zazwyczaj oznaką złego projektowania / zarządzania pamięcią, szczególnie Jeśli nie są zużywane ograniczone zasoby (połączenia, uchwyty, cokolwiek innego, co zwykle prowadzi do wdrożenia IDisposable).

Co sprawia, że musisz to zrobić?

 1
Author: Greg Hurlman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-15 15:34:43

IDisposable interface jest tak naprawdę dla klas, które zawierają niezarządzane zasoby. Jeśli twoja klasa nie zawiera niezarządzanych zasobów, dlaczego potrzebujesz aby zwolnić zasoby, zanim zrobi to garbage collector? W przeciwnym razie po prostu upewnij się, że obiekt jest tworzony tak późno, jak to możliwe i wychodzi z zakresu tak szybko, jak to możliwe.

 1
Author: Tundey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-15 16:48:49

Sorry ale wybrana tutaj odpowiedź jest niepoprawna. Jak kilka osób stwierdziło później Disposable i implementacja IDisposable nie ma nic wspólnego z uwolnieniem pamięci związanej z klasą. NET. Jest głównie i tradycyjnie używany do uwalniania niezarządzanych zasobów, takich jak uchwyty plików itp.

Podczas gdy Twoja aplikacja może wywołać GC.Collect() aby wymusić zbiórkę przez garbage collector to naprawdę będzie miało wpływ tylko na te przedmioty, które są na odpowiednim poziomie generowania w darmowej kolejce. Jest więc możliwe, że jeśli wyczyściłeś wszystkie odniesienia do obiektu, może to być jeszcze kilka wywołań do GC.Collect () przed uwolnieniem rzeczywistej pamięci.

Nie mówisz w swoim pytaniu, dlaczego czujesz potrzebę natychmiastowego zwolnienia pamięci. Rozumiem, że czasami mogą wystąpić nietypowe okoliczności, ale poważnie, w kodach zarządzanych prawie zawsze najlepiej jest pozwolić runtime zająć się zarządzaniem pamięcią.

Prawdopodobnie najlepsza rada, jeśli myślisz Twój kod zużywa pamięć szybciej niż GC go zwalnia, a następnie powinieneś przejrzeć swój kod, aby upewnić się, że żadne obiekty, które nie są już potrzebne, nie są odwoływane do żadnych struktur danych, które masz leżących w statycznych członach itp. Staraj się również unikać sytuacji, w których masz odniesienia do obiektów okrągłych, ponieważ możliwe jest, że te również nie zostaną uwolnione.

 1
Author: Shaun Austin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-25 21:29:10

@Keith,

Zgadzam się ze wszystkimi twoimi zasadami oprócz #4. Dodawanie finalizera powinno odbywać się tylko w bardzo szczególnych okolicznościach. Jeśli Klasa używa niezarządzanych zasobów, należy je wyczyścić w funkcji Dispose(bool). Ta sama funkcja powinna oczyszczać zarządzane zasoby tylko wtedy, gdy bool jest prawdą. Dodanie finalizatora zwiększa złożoność korzystania z obiektu, ponieważ za każdym razem, gdy tworzysz nową instancję, musi ona być również umieszczona w kolejce finalizacji, która jest sprawdzana za każdym razem GC prowadzi cykl zbiórki. Efektywnie oznacza to, że Twój obiekt przetrwa o jeden cykl / generację dłużej niż powinien, więc finalizer może być uruchomiony. Finalizatora nie należy traktować jako"siatki bezpieczeństwa".

GC uruchomi cykl kolekcji tylko wtedy, gdy stwierdzi, że w stercie Gen0 nie ma wystarczającej ilości dostępnej pamięci do wykonania następnej alokacji, chyba że" pomożesz " jej przez wywołanie GC.Collect (), aby wymusić zbiór poza pasmem.

Najważniejsze jest to, że bez względu na co, GC wie tylko jak zwolnić zasoby przez wywołanie metody Dispose (i ewentualnie finalizera, jeśli taka jest zaimplementowana). Do tej metody należy "postąpić właściwie" i oczyścić wszelkie niezarządzane zasoby i polecić innym zarządzanym zasobom wywołanie ich metody rozporządzania. Jest bardzo wydajny w tym, co robi i może samokontroli w dużym stopniu, o ile nie pomagają mu cykle zbierania poza pasmem. To powiedziawszy, brak wezwania GC.Zbieraj wyraźnie nie masz Kontrola kiedy i w jakiej kolejności obiekty zostaną usunięte i zwolniona pamięć.

 1
Author: Scott Dorman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 10:26:30

Jeśli nie chcesz (lub nie możesz) zaimplementować IDisposable na swojej klasie, możesz wymusić takie usuwanie śmieci (ale jest to powolne) -

GC.Collect();
 0
Author: Seibar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-15 15:33:55

Możesz mieć deterministyczne niszczenie obiektów w c++

Nigdy nie chcesz zadzwonić do GC.Zbieraj, to bałagan z samo dostrajania garbage collector wykryć ciśnienie pamięci i w niektórych przypadkach nie robić nic innego niż zwiększyć bieżącą generację każdego obiektu na stercie.

Dla tych, którzy zamieszczają IDisposable odpowiedzi. Wywołanie metody Dispose nie niszczy obiektu, jak opisuje asker.

 0
Author: Brian Leahy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-25 21:18:25

@Keith:

IDisposable jest dla zarządzanych zasobów.

Finalizatory są dla niezarządzanych zasobów.

Przepraszam, ale to jest złe. Zazwyczaj finalizator nie robi nic. Jeśli jednak wzór usuwania został poprawnie zaimplementowany, finalizator próbuje wywołać Dispose.

Dispose ma dwa zadania:

  • wolne niezarządzane zasoby i
  • wolne zagnieżdżone zarządzane zasoby.

I tu twoja wypowiedź wchodzi w grę, ponieważ prawdą jest, że podczas finalizacji obiekt nigdy nie powinien próbować uwolnić zagnieżdżonych zarządzanych zasobów, ponieważ mogły one już zostać uwolnione. Musi jednak nadal uwalniać niezarządzane zasoby.

Finalizery nie mają jednak innego zadania niż wywołanie Dispose i zakazanie dotykania zarządzanych obiektów. Dispose, wywołane ręcznie (lub przez Using), uwolni wszystkie niezarządzane zasoby i przekaże wiadomość Dispose do zagnieżdżonych obiektów (i metod klasy bazowej), ale to nigdy nie będzie wolne Dowolna (Zarządzana) pamięć.

 0
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-26 09:11:17

Konrad Rudolph-tak, normalnie finalista nic nie robi. Nie powinieneś go wdrażać, chyba że masz do czynienia z niezarządzanymi zasobami.

Następnie, gdy go zaimplementujesz, używasz wzorca dispose Microsoftu (Jak już opisano)

  • public Dispose() calls protected Dispose(true) - zajmuje się zarówno zarządzanymi, jak i niezarządzanymi zasobami. Wywołanie {[2] } powinno powstrzymać finalizację.

  • ~Finalize calls protected Dispose(false) - dotyczy tylko zasobów niezarządzanych. Zapobiega to niezarządzane wycieki pamięci, jeśli nie zadzwonisz do public Dispose()

~Finalize jest powolny i nie powinien być używany, chyba że masz niezarządzane zasoby do czynienia z.

Zarządzane zasoby nie mogą wyciekać pamięci, mogą tylko marnować zasoby dla bieżącej aplikacji i spowalniać jej zbieranie śmieci. Niezarządzane zasoby mogą wyciekać, a ~Finalize jest najlepszą praktyką, aby upewnić się, że nie.

W obu przypadkach using jest najlepszą praktyką.

 0
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-28 16:06:28

@Curt Hagenlocher-to z powrotem do przodu. Nie mam pojęcia, dlaczego tak wielu głosowało, kiedy to jest złe.

IDisposable jest dla zarządzanych zasobów.

Finalizatory są dlaniezarządzanych zasobów.

Tak długo, jak używasz tylko zarządzanych zasobów, zarówno @ Jon Limjap, jak i ja jesteśmy całkowicie poprawni.

Dla klas, które używają niezarządzanych zasobów (i pamiętaj, że zdecydowana większość klas. Net Nie) odpowiedź Patrika jest wyczerpująca i najlepsza praktyka.

Unikaj używania GC.Collect - jest to powolny sposób radzenia sobie z zarządzanymi zasobami i nie robi nic z niezarządzanymi, chyba że poprawnie zbudowałeś swoje ~ Finalizery.


Usunąłem komentarz moderatora z pierwotnego pytania zgodnie z https://stackoverflow.com/questions/14593/etiquette-for-modifying-posts

 0
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:02

W odpowiedzi na pierwotne pytanie, z informacjami podanymi do tej pory przez oryginalny plakat, jest 100% pewne, że nie wie wystarczająco dużo o programowaniu w. NET, aby nawet otrzymać odpowiedź: użyj GC.Collect (). Powiedziałbym, że jest 99.99% prawdopodobne, że naprawdę nie musi używać GC.Collect() w ogóle, jak wskazuje większość plakatów.

Poprawna odpowiedź sprowadza się do " niech GC wykonuje swoją pracę. Kropka. Masz inne zmartwienia. Ale może warto rozważyć, czy i kiedy należy pozbywać się lub czyścić określone obiekty, i czy trzeba zaimplementować IDisposable i ewentualnie sfinalizować w swojej klasie.'

Odnośnie postu Keitha i jego zasady # 4:

Niektóre plakaty mylą regułę 3 i 4. Zasada 4 Keitha jest całkowicie poprawna, jednoznacznie. To jedna z czterech zasad, która w ogóle nie wymaga edycji. Chciałbym nieco przeformułować niektóre z jego innych zasad, aby je jaśniejsze, ale są one zasadniczo poprawne, jeśli je przeanalizować poprawnie, a właściwie Przeczytaj cały post, aby zobaczyć, jak rozszerza się na nich.

  1. Jeśli twoja klasa nie używa niezarządzanego zasobu i nigdy nie tworzy instancji innego obiektu klasy, który sam używa, bezpośrednio lub ostatecznie, niezarządzanego obiektu( np. klasy, która implementuje IDisposable), wtedy nie byłoby potrzeby, aby Twoja klasa zaimplementowała IDisposable sama, lub nawet wywołała.pozbądź się wszystkiego. (W takim przypadku głupio jest myśleć, że faktycznie musisz natychmiast zwolnij pamięć z wymuszonym GC.)

  2. Jeśli twoja klasa używa niezarządzanego zasobu lub tworzy instancję innego obiektu, który sam implementuje IDisposable, wtedy twoja klasa powinna:

    A) usunąć / zwolnić je natychmiast w kontekście lokalnym, w którym zostały utworzone, lub...

    B) zaimplementować IDisposable we wzorze zalecanym w poście Keitha, w kilku tysiącach miejsc w Internecie, lub dosłownie w około 300 książkach.

    B. 1) Ponadto, jeśli (b) i jest to zasób niezarządzany, który został otwarty, zarówno IDisposable, jak i Finalize powinny być zawsze zaimplementowane, zgodnie z zasadą Keitha #4.
    W tym kontekście Finalize absolutely jest w pewnym sensie siatką bezpieczeństwa: jeśli ktoś tworzy instancję Twojego IDisposable obiektu, który używa niezarządzanego zasobu, i nie zadzwoni do dispose, to Finalize jest ostatnią szansą dla Twojego obiektu, aby prawidłowo zamknąć niezarządzany zasób.
    (Finalize powinno to zrobić wywołując Dispose w taki sposób że metoda Dispose pomija uwalnianie czegokolwiek poza niezarządzanym zasobem. Alternatywnie, jeśli metoda Dispose Twojego obiektu jest wywoływana poprawnie przez cokolwiek, co utworzyło instancję Twojego obiektu, to zarówno przekazuje wywołanie Dispose do wszystkich identyfikowalnych obiektów, które utworzyło instancję, jak i zwalnia niezarządzane zasoby, kończąc na wywołaniu w celu powstrzymania Finalize na Twoim obiekcie, co oznacza, że wpływ użycia Finalize jest zmniejszony, jeśli twój obiekt jest usuwany prawidłowo przez wywołującego. Wszystkie te punkty są zawarte w poście Keitha, BTW.)

    B. 2) jeśli twoja klasa implementuje IDisposable tylko dlatego, że musi zasadniczo przekazać Disposable do IDisposable obiektu, który utworzył instancję, to w takim przypadku nie implementuj metody Finalize w swojej klasie. Finalize służy do obsługi sprawy, że oba Dispose nigdy nie zostały wywołane przez cokolwiek, co utworzyło instancję Twojego obiektu, a niezarządzany zasób został wykorzystany, który nadal nie został opublikowany.

W skrócie, odnośnie Post Keitha, jest całkowicie poprawny, a ten post jest najbardziej poprawną i kompletną odpowiedzią, moim zdaniem. Może on używać krótkich wypowiedzi, które niektórzy uważają za " złe " lub sprzeciwiają się, ale jego pełny post rozszerza się na użycie Finalize całkowicie i jest absolutnie poprawny. Pamiętaj, aby przeczytać jego post całkowicie przed skokiem na jednym z zasad lub wstępnych oświadczeń w swoim poście.

 0
Author: Jaycephus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-23 01:25:58

Jeśli MyClass implementuje IDisposable, możesz to zrobić.

MyClass.Dispose();

Najlepsza praktyka w C # to:

using( MyClass x = new MyClass() ) {
    //do stuff
}
/ Align = "left" /
 -1
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-15 15:32:40