Should I Dispose () DataSet and DataTable?

DataSet i DataTable implementują IDisposable, więc, według konwencjonalnych najlepszych praktyk, powinienem nazwać ich metody Disposable ().

Jednak z tego, co do tej pory czytałem, DataSet i DataTable nie mają właściwie żadnych niezarządzanych zasobów, więc Dispose() nie robi zbyt wiele.

Plus, nie mogę po prostu użyć using(DataSet myDataSet...) ponieważ DataSet ma kolekcję DataTables.

Więc, żeby być bezpiecznym, musiałbym przejść przez myDataSet.Tabel, pozbywać się każdej z tabel danych, następnie pozbywać zbioru danych.

Więc, czy warto wywoływać Dispose () na wszystkich moich Datasetach i DataTables?

Dodatek:

Dla tych z Was, którzy uważają, że zbiór danych powinien być: Ogólnie, wzorzec usuwania polega na użyciu using lub try..finally, ponieważ chcesz zagwarantować, że Dispose() zostanie wywołane.

Jednak szybko robi się to brzydkie jak na kolekcję. Na przykład, co zrobić, jeśli jedno z wywołań Dispose () wyrzuci wyjątek? Czy ty połknąć (co jest "złe") tak, że można kontynuować, aby pozbyć się następnego elementu?

Czy sugerujesz, żebym zadzwonił do myDataSet?Dispose () i zapomnij o usuwaniu DataTables w myDataSet.Stoły?
Author: mbeckish, 2009-05-27

10 answers

Oto kilka dyskusji wyjaśniających, dlaczego Dispose nie jest konieczny dla zbioru danych.

Pozbywać się czy nie pozbywać ?:

Metoda Dispose w zbiorze danych istnieje tylko ze względu na efekt uboczny dziedziczenia-innymi słowy, nie robi nic użytecznego w finalizacji.

Czy Dispose należy wywoływać na obiektach DataTable i DataSet? zawiera pewne wyjaśnienie z MVP:

System.przestrzeń nazw danych (ADONET) nie zawiera zasoby niezarządzane. W związku z tym nie ma potrzeby pozbywania się tych o ile nie dodałeś do tego czegoś specjalnego.

Zrozumienie metody usuwania i zbiorów danych? mA komentarz od autorytetu:

W pratice rzadko pozbywamy się zbioru danych, ponieważ przynosi on niewielkie korzyści "

Tak więc konsensus jest taki, że nie ma obecnie dobrego powodu, aby wezwać Dispose na Zestaw danych.

 131
Author: DOK,
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
2016-07-13 21:40:25

Aktualizacja (Grudzień 1, 2009):

Chciałbym zmienić tę odpowiedź i przyznać, że oryginalna odpowiedź była błędna.

Oryginalna analiza czy stosuje się do obiektów wymagających finalizacji – a punkt, że praktyki nie powinny być akceptowane na powierzchni bez dokładnego, dogłębnego zrozumienia nadal stoi.

Okazuje się jednak, że zbiory danych, DataViews, DataTables tłumią finalizację w swoich konstruktorach – to dlatego wywołanie Dispose () na nich jawnie nic nie robi.

Prawdopodobnie dzieje się tak dlatego, że nie mają niezarządzanych zasobów; więc pomimo faktu, że MarshalByValueComponent zapewnia uprawnienia dla niezarządzanych zasobów, te konkretne implementacje nie mają takiej potrzeby i dlatego mogą zrezygnować z finalizacji.

(że autorzy. NET zadbają o to, aby uniknąć finalizacji na samych typach, które normalnie zajmują najwięcej pamięci, mówi o znaczeniu tego praktyka w ogóle dla finalizowalnych typów.)

Niezależnie od tego, że te szczegóły są nadal niedostatecznie udokumentowane, ponieważ powstanie. NET Framework (prawie 8 lat temu) jest dość zaskakujące (to, że jesteś zasadniczo pozostawiony do własnych urządzeń, aby przesiać choć sprzeczne, niejednoznaczne materiały do złożenia elementów razem jest frustrujące czasami, ale zapewnia pełniejsze zrozumienie frameworku, na którym polegamy na co dzień).

Po wielu lekturach, oto mój zrozumienie:

Jeśli obiekt wymaga finalizacji, to może zajmuje pamięć dłużej niż musi – oto dlaczego: a) każdy typ, który definiuje Destruktor (lub dziedziczy od typu, który definiuje Destruktor) jest uważany za finalizowalny; b) przy alokacji (przed uruchomieniem konstruktora) wskaźnik jest umieszczany w kolejce finalizacji; c) Obiekt finalizowalny zwykle wymaga odzyskania 2 kolekcji (zamiast standardowego 1); d) tłumienie finalizacji nie usuwa obiektu z kolejki finalizacji (zgodnie z raportem !FinalizeQueue w SOS) To polecenie jest mylące; Wiedza o tym, jakie obiekty znajdują się w kolejce finalizacji (sama w sobie), nie jest pomocna; Wiedza o tym, jakie obiekty znajdują się w kolejce finalizacji i nadal wymagają finalizacji, byłaby pomocna (czy istnieje do tego polecenie?)

Tłumienie finalizacji wyłącza się nieco w nagłówku obiektu, wskazując runtime, że nie musi wywoływać Finalizera (nie trzeba przesunąć kolejkę darmową); pozostaje ona w kolejce finalizacji (i nadal jest zgłaszana przez !FinalizeQueue in SOS)

Klasy DataTable, DataSet, DataView są zakorzenione w MarshalByValueComponent, finalizowalnym obiekcie, który może (potencjalnie) obsługiwać niezarządzane zasoby

    Ponieważ DataTable, DataSet, DataView nie wprowadzają niezarządzanych zasobów, tłumią finalizację w swoich konstruktorach.]}
  • chociaż jest to nietypowy wzór, uwalnia rozmówca od konieczności martwienia się o wywołanie po użyciu
  • To, a także fakt, że zbiory danych mogą być potencjalnie współdzielone między różnymi zbiorami danych, jest prawdopodobnie powodem, dla którego zbiory danych nie dbają o to, aby pozbyć się potomnych zbiorów danych.]}
  • oznacza to również, że obiekty te pojawią się podFinalizeQueue in SOS
  • jednak obiekty te nadal powinny być odzyskiwalne po pojedynczym zbiorze, podobnie jak ich niekompletne odpowiedniki

4 (nowe linki):

Oryginał Odpowiedź:

Istnieje wiele mylących i ogólnie bardzo słabych odpowiedzi na ten temat-każdy, kto tu wylądował, powinien zignorować hałas i uważnie przeczytać poniższe odniesienia.

Bez wątpienia, Dispose powinno być wywoływane na dowolnych Finalizowalnych obiektach.

DataTables Finalizowalne.

Wywołanie Dispose znacząco przyspiesza odzyskiwanie pamięci.

MarshalByValueComponent calls GC.SuppressFinalize (this) w jego Dispose () - pomijanie tego oznacza czekanie na dziesiątki, jeśli nie setki zbiorów Gen0, zanim pamięć zostanie odzyskana:

Z tym podstawowym rozumieniem finalizacji mamy można już wydedukować kilka bardzo ważnych rzeczy:

Po pierwsze, obiekty, które wymagają finalizacji żyć dłużej niż przedmioty, które nie. W rzeczywistości mogą żyć o wiele dłużej. Załóżmy na przykład, że obiekt, który jest w gen2 musi być sfinalizowane. Finalizacja zostanie zaplanowana, ale obiekt jest nadal w gen2, więc będzie nie będą ponownie zbierane do następnego kolekcja gen2 To może być rzeczywiście bardzo długo, a w rzeczywistości, jeśli wszystko idzie dobrze to będzie dawno, bo Kolekcje gen2 są kosztowne i dlatego chcemy, aby zdarza się bardzo rzadko. Starsze obiekty wymagające finalizacji mogą trzeba czekać na dziesiątki, jeśli nie setki kolekcji gen0 przed ich przestrzeń jest odzyskana.

Po drugie, obiekty wymagające finalizacji wyrządzić szkody uboczne. Ponieważ wewnętrzne wskaźniki obiektów muszą pozostać ważne, nie tylko obiekty bezpośrednio wymagające finalizacji w pamięci, ale wszystko, co obiekt odnosi się bezpośrednio i pośrednio do, również pozostanie w pamięci. Jeśli ogromny drzewo obiektów zostało zakotwiczone przez pojedynczy obiekt, który wymaga finalizacji, następnie całe drzewo pozostaną, potencjalnie na długo czas, o którym rozmawialiśmy. On dlatego ważne, aby używać finalizerów oszczędnie i umieszczać je na przedmiotach które mają jak najmniej obiektów wewnętrznych wskazówki jak to możliwe. In the tree przykład, który właśnie dałem, można łatwo unikaj problemu, przesuwając zasoby wymagające finalizacji do oddzielny obiekt i utrzymywanie odniesienie do tego obiektu w katalogu głównym z drzewa. Z tą skromną zmianą tylko jeden obiekt (mam nadzieję, że ładny mały przedmiot) będzie trwać i koszt finalizacji jest zminimalizowany.

Wreszcie, obiekty wymagające finalizacji Utwórz pracę dla wątku finalizer. Jeśli proces finalizacji jest kompleksowy, jedyny wątek finalizer wyda dużo czasu na wykonanie tych kroków, które mogą powodować zaległości w pracy i dlatego powoduje, że więcej obiektów pozostaje czekam na finalizację. Dlatego, niezwykle ważne jest, aby finalizatorzy wykonują tak mało pracy, jak możliwe. Pamiętaj też, że chociaż wszystkie wskaźniki obiektu pozostają ważne podczas finalizacji, to może być przypadku, że te wskaźniki prowadzą do obiekty, które już zostały sfinalizowane i dlatego może być mniej niż przydatne. Generalnie najbezpieczniej jest unikaj następujących wskaźników obiektów w kod finalizacyjny, mimo że wskaźniki są ważne. Bezpieczny, krótki ścieżka kodu finalizacji jest najlepsza.

Weź to od kogoś, kto widział 100 MBs nie odwołujących się DataTables w Gen2: jest to niezwykle ważne i całkowicie pominięte przez odpowiedzi w tym wątku.

Referencje:

1 - http://msdn.microsoft.com/en-us/library/ms973837.aspx

2 - http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD! 1104. entry http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage-collector-performance-using-finalizedispose-pattern.aspx

3 - http://codeidol.com/csharp/net-framework/Inside-the-CLR/Automatic-Memory-Management/

 119
Author: Nariman,
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
2016-02-10 01:55:37

Powinieneś założyć, że robi coś użytecznego i wywołać Dispose nawet jeśli nie robi nic w current . Wcielenia NET Framework, nie ma gwarancji, że tak pozostanie w przyszłych wersjach, co prowadzi do nieefektywnego wykorzystania zasobów.

 21
Author: Nuno,
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
2009-05-26 23:25:02

Nawet jeśli obiekt nie ma niezarządzanych zasobów, usuwanie może pomóc GC poprzez łamanie Wykresów obiektów. Ogólnie rzecz biorąc, jeśli obiekt implementuje IDisposable, należy wywołać Disposable ().

To, czy Dispose() rzeczywiście coś robi, czy nie, zależy od podanej klasy. W przypadku zbioru danych implementacja Dispose() jest dziedziczona od MarshalByValueComponent. Usuwa się z kontenera i wywołuje usunięte Zdarzenie. Poniżej znajduje się kod źródłowy (demontowany za pomocą. NET Reflector):

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this)
        {
            if ((this.site != null) && (this.site.Container != null))
            {
                this.site.Container.Remove(this);
            }
            if (this.events != null)
            {
                EventHandler handler = (EventHandler) this.events[EventDisposed];
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }
        }
    }
}
 16
Author: dwieczor,
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
2009-05-27 08:39:05

Czy sam tworzysz bazy danych? Ponieważ iteracja poprzez dzieci dowolnego obiektu (jak w zbiorze danych.Tabele) zazwyczaj nie są potrzebne, ponieważ zadaniem rodzica jest pozbycie się wszystkich jego członków potomnych.

Ogólnie, zasada jest taka: jeśli go stworzyłeś i implementuje IDisposable, pozbądź się go. Jeśli go nie utworzyłeś, to nie usuwaj go, jest to zadanie obiektu nadrzędnego. Ale każdy obiekt może mieć specjalne reguły, sprawdź dokumentację.

Dla. Net 3.5, to jawnie mówi "pozbądź się go, gdy już nie używasz", więc tak bym zrobił.

 7
Author: Michael Stum,
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
2009-05-27 08:49:48

Wywołuję dispose, gdy obiekt implementuje IDisposable. Nie bez powodu.

Zbiory danych mogą być ogromnymi wieprzami pamięci. Im szybciej zostaną oznaczone do czyszczenia, tym lepiej.

Update

Minęło 5 lat odkąd odpowiedziałem na to pytanie. Nadal zgadzam się z moją odpowiedzią. Jeśli istnieje metoda dispose, powinna zostać wywołana po zakończeniu pracy z obiektem. Interfejs IDispose został zaimplementowany nie bez powodu.

 6
Author: Chuck Conway,
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
2014-03-24 16:53:54

Jeśli twoim zamiarem lub kontekstem tego pytania jest zbieranie śmieci, możesz ustawić zbiory danych i bazy danych na null jawnie lub użyć słowa kluczowego i pozwolić im wyjść poza zakres. Dispose nie robi wiele, jak mówił wcześniej Tetraneutron. GC będzie zbierać obiekty zestawu danych, które nie są już odwołane, a także te, które są poza zakresem.

Naprawdę chciałbym, aby tak zmusili ludzi do głosowania, aby rzeczywiście napisać komentarz przed odrzuceniem odpowiedzi.

 4
Author: Srikar Doddi,
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
2009-05-26 23:40:10

Zbiory danych implementują IDisposable dokładny MarshalByValueComponent, który implementuje IDisposable. Ponieważ zbiory danych są zarządzane, nie ma realnej korzyści z wywołania dispose.

 1
Author: Tetraneutron,
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
2009-05-26 23:18:25

Spróbuj użyć funkcji Clear (). To działa świetnie dla mnie do usuwania.

DataTable dt = GetDataSchema();
//populate dt, do whatever...
dt.Clear();
 0
Author: Hasan Savran,
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
2013-11-20 16:49:15

Przede wszystkim chciałbym sprawdzić, co Dispose robi z zestawem danych. Może użycie reflektora z redgate pomoże.

 -1
Author: crauscher,
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
2009-05-26 23:15:06