Aktualizacja (1 grudnia 2009 r.):
Chciałbym zmienić tę odpowiedź i przyznać, że pierwotna odpowiedź była błędna.
Oryginalna analiza ma zastosowanie do obiektów wymagających finalizacji - a argument, że praktyki nie powinny być akceptowane na powierzchni bez dokładnego i dogłębnego zrozumienia, nadal obowiązuje.
Okazuje się jednak, że DataSets, DataViews, DataTables blokują finalizację w swoich konstruktorach - dlatego wywołanie na nich Dispose () jawnie nic nie robi.
Przypuszczalnie dzieje się tak, ponieważ nie mają niezarządzanych zasobów; więc pomimo faktu, że MarshalByValueComponent uwzględnia rezerwy na niezarządzane zasoby, te konkretne wdrożenia nie mają takiej potrzeby i dlatego mogą zrezygnować z finalizacji.
(Autorzy .NET zadbają o to, aby finalizacja tego typu typów, które zwykle zajmują najwięcej pamięci, świadczy o znaczeniu tej praktyki w ogóle dla typów finalizowanych).
Niezależnie od tego, że szczegóły te są nadal niedokumentowane, odkąd system .NET Framework (prawie 8 lat temu) jest dość zaskakujący (że zasadniczo pozostawiasz swoje własne urządzenia do przesiewania przez sprzeczne, niejednoznaczne materiały, aby połączyć elementy razem jest czasami frustrujący, ale zapewnia pełniejsze zrozumienie ram, na których codziennie polegamy).
Po wielu lekturach, oto moje zrozumienie:
Jeśli obiekt wymaga finalizacji, może zajmować pamięć dłużej niż jest to konieczne - oto dlaczego: a) Każdy typ, który definiuje destruktor (lub dziedziczy po typie, który definiuje destruktor) jest uznawany za finalizowalny; b) Przy alokacji (przed uruchomieniem konstruktora) wskaźnik umieszczany jest w kolejce finalizacji; c) Obiekt finalizowalny zwykle wymaga
Wyłączenia finalizacji nieco wyłącza nagłówek obiektu, wskazując środowisku wykonawczemu, że nie musi być wywoływany jego finalizator (nie musi przenosić kolejki FReachable); Pozostaje w kolejce finalizacji (i nadal jest zgłaszany przez! FinalizeQueue w SOS) 2 kolekcji. odzyskania (zamiast standardowej 1); d) Pomijanie finalizacji nie usuwa obiektu z kolejki finalizacji (jak informuje! FinalizeQueue w SOS) To polecenie wprowadza w błąd; Wiedza, które obiekty znajdują się w kolejce finalizacji (sama w sobie), nie jest pomocna; Pomocna byłaby wiedza, które obiekty znajdują się w kolejce finalizacji i nadal wymagają finalizacji (czy istnieje na to polecenie?)
Wszystkie klasy DataTable, DataSet, DataView są zakorzenione w MarshalByValueComponent, finalizowanym 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 niezwykły wzór, uwalnia dzwoniącego od konieczności martwienia się o połączenie Usuń po użyciu
- To oraz fakt, że DataTables mogą być potencjalnie współużytkowane przez różne DataSets, jest prawdopodobnie przyczyną, dla której DataSets nie chce pozbywać się potomnych DataTables
- Oznacza to również, że obiekty te pojawią się pod! FinalizeQueue w SOS
- Jednak obiekty te nadal powinny być możliwe do odzyskania po pojedynczej kolekcji, podobnie jak ich nieukończone odpowiedniki
4 (nowe referencje):
Oryginalna 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 należy wywoływać Dispose na dowolnych obiektach, które można sfinalizować.
Tabele danych można sfinalizować.
Wywołanie Dispose znacznie przyspiesza odzyskiwanie pamięci.
MarshalByValueComponent wywołuje GC.SuppressFinalize (this) w swoim Dispose () - pominięcie tego oznacza konieczność oczekiwania na dziesiątki, jeśli nie setki kolekcji Gen0, zanim pamięć zostanie odzyskana:
Dzięki temu podstawowemu zrozumieniu finalizacji możemy już wywnioskować kilka bardzo ważnych rzeczy:
Po pierwsze, obiekty wymagające finalizacji żyją dłużej niż obiekty, które tego nie robią. W rzeczywistości mogą żyć znacznie dłużej. Załóżmy na przykład, że obiekt należący do gen2 musi zostać sfinalizowany. Finalizacja zostanie zaplanowana, ale obiekt nadal znajduje się w gen2, więc nie zostanie ponownie zebrany, dopóki nie nastąpi kolejna kolekcja gen2. To może być naprawdę bardzo długi czas, a tak naprawdę, jeśli wszystko pójdzie dobrze, minie dużo czasu, ponieważ kolekcje gen2 są kosztowne i dlatego chcemy, aby zdarzały się bardzo rzadko. Starsze obiekty wymagające finalizacji mogą potrzebować dziesiątek, jeśli nie setek kolekcji gen0, zanim ich przestrzeń zostanie odzyskana.
Po drugie, obiekty wymagające finalizacji powodują uszkodzenia dodatkowe. Ponieważ wewnętrzne wskaźniki obiektów muszą pozostać ważne, nie tylko obiekty bezpośrednio wymagające finalizacji pozostaną w pamięci, ale wszystko, do czego odnosi się obiekt, bezpośrednio i pośrednio, pozostanie również w pamięci. Gdyby ogromne drzewo obiektów zostało zakotwiczone przez pojedynczy obiekt, który wymagał sfinalizowania, całe drzewo pozostałoby, potencjalnie przez długi czas, jak właśnie dyskutowaliśmy. Dlatego ważne jest oszczędne używanie finalizatorów i umieszczanie ich na obiektach, które mają jak najmniej wewnętrznych wskaźników obiektów. W przykładzie drzewa, który właśnie podałem, możesz łatwo uniknąć problemu, przenosząc zasoby wymagające finalizacji do osobnego obiektu i zachowując odniesienie do tego obiektu w katalogu głównym drzewa.
Wreszcie obiekty wymagające finalizacji tworzą pracę dla wątku finalizatora. Jeśli proces finalizacji jest skomplikowany, jedyny wątek finalizatora poświęci dużo czasu na wykonanie tych kroków, co może spowodować zaległości w pracy, a tym samym spowodować, że więcej obiektów pozostanie w oczekiwaniu na finalizację. Dlatego niezwykle ważne jest, aby finaliści wykonali jak najmniej pracy. Pamiętaj również, że chociaż wszystkie wskaźniki obiektów pozostają ważne podczas finalizacji, może się zdarzyć, że wskaźniki te prowadzą do obiektów, które zostały już sfinalizowane i dlatego mogą być mniej niż przydatne. Zasadniczo najbezpieczniej jest unikać śledzenia wskaźników obiektu w kodzie finalizacji, nawet jeśli wskaźniki są prawidłowe. Najlepsza jest bezpieczna, krótka ścieżka kodu finalizacji.
Weź to od kogoś, kto widział 100 MB danych DataTables bez odniesienia w Gen2: jest to niezwykle ważne i całkowicie pomijane przez odpowiedzi w tym wątku.
Bibliografia:
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/