Czy powinieneś ustawić wszystkie obiekty na null
( Nothing
w VB.NET) po ich zakończeniu?
Rozumiem, że w .NET bardzo ważne jest, aby pozbyć się wszelkich instancji obiektów implementujących IDisposable
interfejs w celu zwolnienia niektórych zasobów, chociaż obiekt może nadal być czymś po jego usunięciu (stąd isDisposed
właściwość w formularzach), więc zakładam, że nadal może on rezydować w pamięci czy przynajmniej częściowo?
Wiem również, że gdy obiekt wykracza poza zakres, jest on następnie oznaczany do kolekcjonowania gotowy do następnego przejścia modułu wyrzucania elementów bezużytecznych (chociaż może to zająć trochę czasu).
Mając to na uwadze, czy ustawienie to null
przyspieszy system zwalniający pamięć, ponieważ nie musi się zorientować, że nie jest już objęty zakresem i czy są to jakieś złe skutki uboczne?
Artykuły MSDN nigdy nie robią tego w przykładach i obecnie robię to, ponieważ nie widzę szkody. Jednak natknąłem się na mieszankę opinii, więc wszelkie komentarze są przydatne.
Odpowiedzi:
Karl ma absolutną rację, po użyciu nie trzeba ustawiać obiektów na zero. Jeśli obiekt implementuje
IDisposable
, po prostu upewnij się, że dzwonisz,IDisposable.Dispose()
gdy skończysz z tym obiektem (zawiniętym wtry
...finally
lubusing()
blok). Ale nawet jeśli nie pamiętasz, aby zadzwonićDispose()
, metoda finalizatora obiektu powinnaDispose()
cię wołać .Myślałem, że to dobre traktowanie:
i to
Nie ma sensu próbować zgadywać GC i jej strategii zarządzania, ponieważ jest to samostrojenie i nieprzejrzyste. Odbyła się dobra dyskusja na temat wewnętrznych działań z Jeffreyem Richterem na Dot Net Rocks: Jeffrey Richter na temat Windows Memory Model i książki Richters CLR poprzez C # rozdział 20 ma świetne podejście:
źródło
Innym powodem, dla którego należy unikać ustawiania obiektów na wartość NULL po ich zakończeniu, jest fakt, że mogą one dłużej utrzymywać je przy życiu.
na przykład
pozwoli obiektowi określonemu przez someType zostać GC po wywołaniu „DoSomething”, ale
może czasem utrzymywać obiekt przy życiu aż do końca metody. JIT będzie zwykle optymalizowana dala przyporządkowanie do zerową , więc w obu bitów kodu do góry koniec jest taki sam.
źródło
GC.KeepAlive(someType);
Zobacz ericlippert.com/2013/06/10/construction-destructionNie, nie zeruj obiektów. Możesz sprawdzić http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx, aby uzyskać więcej informacji, ale ustawienie rzeczy zerowanie nic nie zrobi, oprócz wyczyszczenia kodu.
źródło
Również:
źródło
Ogólnie rzecz biorąc, nie ma potrzeby zerowania obiektów po użyciu, ale w niektórych przypadkach uważam, że to dobra praktyka.
Jeśli obiekt implementuje IDisposable i jest przechowywany w polu, myślę, że warto go wyzerować, aby uniknąć użycia usuwanego obiektu. Błędy tego rodzaju mogą być bolesne:
Dobrze jest zerować pole po jego usunięciu i uzyskać NullPtrEx bezpośrednio w wierszu, w którym pole jest ponownie używane. W przeciwnym razie możesz napotkać jakiś tajemniczy błąd wzdłuż linii (w zależności od tego, co dokładnie robi DoSomething).
źródło
.Dispose()
. Jeśli go znajdziesz, nie używasz poprawnie IDisposable. Jedynym zastosowaniem dla obiektu jednorazowego użytku powinno być ograniczenie bloku użytkowego. A po użyciu bloku nie maszmyField
już nawet dostępu do niego . A w bloku używającym, ustawienienull
to nie jest wymagane, blok użytkowy zbywa obiekt za ciebie.Możliwe, że twój kod nie jest wystarczająco ściśle skonstruowany, jeśli odczuwasz potrzebę
null
zmiennych.Istnieje wiele sposobów ograniczenia zakresu zmiennej:
Jak wspomniał Steve Tranby
Podobnie możesz po prostu użyć nawiasów klamrowych:
Uważam, że używanie nawiasów klamrowych bez „nagłówka” w celu naprawdę wyczyszczenia kodu i uczynienia go bardziej zrozumiałym.
źródło
Jedynym momentem, w którym powinieneś ustawić zmienną na null, jest to, kiedy zmienna nie wykracza poza zakres i nie potrzebujesz już danych z nią powiązanych. W przeciwnym razie nie ma takiej potrzeby.
źródło
Zasadniczo nie trzeba ustawiać wartości null. Załóżmy jednak, że masz w swojej klasie funkcję resetowania.
Następnie możesz to zrobić, ponieważ nie chcesz wywoływać funkcji usuwania dwukrotnie, ponieważ niektóre z funkcji Dispose mogą nie zostać poprawnie zaimplementowane i zgłoszą wyjątek System.ObjectDisposed.
źródło
tego rodzaju „nie ma potrzeby ustawiania obiektów na zero po użyciu” nie jest całkowicie dokładne. Czasami musisz NULL zmienną po jej usunięciu.
Tak, powinieneś ZAWSZE zadzwonić
.Dispose()
lub.Close()
coś, co ma to po zakończeniu. Czy to uchwyty plików, połączenia z bazą danych czy obiekty jednorazowe.Oddzielny jest bardzo praktyczny wzór LazyLoad.
Muszę powiedzieć i wystąpienia
ObjA
zclass A
.Class A
ma własność publiczną o nazwiePropB
odclass B
.Wewnętrznie
PropB
używa zmiennej prywatnej_B
i domyślnie ma wartość null. GdyPropB.Get()
jest używany, sprawdza, czy_PropB
ma wartość null, a jeśli tak, otwiera zasoby potrzebne do utworzenia instancjiB
w_PropB
. Następnie powraca_PropB
.Z mojego doświadczenia wynika, że jest to naprawdę przydatna sztuczka.
Gdy pojawia się potrzeba zerowania, jeśli zresetujesz lub zmienisz A w taki sposób, że zawartość
_PropB
była potomkiem poprzednich wartościA
, będziesz musiał usunąć i_PropB
zerować, aby LazyLoad mógł zresetować, aby pobrać poprawną wartość JEŻELI kod wymaga tego.Jeśli tylko to zrobisz
_PropB.Dispose()
i wkrótce potem spodziewasz się, że sprawdzenie LazyLoad zakończy się sukcesem, nie będzie to zero, a będziesz patrzeć na nieaktualne dane. W efekcie musisz go zerować poDispose()
prostu, aby się upewnić.I pamiętaj, żeby to było inaczej, ale mam kod teraz wykazujące to zachowanie po
Dispose()
na zasadzie_PropB
a poza wywołanie funkcji, które zrobił Dispose (a więc prawie poza zakresem), prywatna prop jeszcze nie jest zerowa, i wciąż są tam nieaktualne dane.Ostatecznie zbywana właściwość zostanie unieważniona, ale z mojej perspektywy było to niedeterministyczne.
Głównym powodem, jak wspomina dbkk, jest to, że kontener nadrzędny (
ObjA
zPropB
) zachowuje instancję_PropB
w zakresie, pomimoDispose()
.źródło
W niektórych przypadkach sensowne jest odwołanie do wartości zerowej. Na przykład, gdy piszesz kolekcję - jak kolejka priorytetowa - i zgodnie z umową, nie powinieneś utrzymywać tych obiektów przy życiu dla klienta po tym, jak klient usunie je z kolejki.
Ale tego rodzaju rzeczy mają znaczenie tylko w długowiecznych kolekcjach. Jeśli kolejka nie przetrwa końca funkcji, w której została utworzona, ma to o wiele mniejsze znaczenie.
Ogólnie rzecz biorąc, naprawdę nie powinieneś się tym przejmować. Pozwól kompilatorowi i GC wykonywać swoje zadania, abyś mógł wykonać swoje.
źródło
Zobacz także ten artykuł: http://www.codeproject.com/KB/cs/idisposable.aspx
W większości przypadków ustawienie obiektu na null nie ma żadnego efektu. Jedyny raz, kiedy powinieneś to zrobić, to pracując z „dużym obiektem”, który ma rozmiar większy niż 84 KB (np. Bitmapy).
źródło
Stephen Cleary bardzo dobrze wyjaśnia w tym poście: Czy należy ustawić zmienne na Null, aby wspomóc zbieranie śmieci?
Mówi:
Ważną rzeczą, którą powinniśmy rozważyć, są pola statyczne .
Wniosek:
źródło
Wierzę, że z projektu implementatorów GC nie można przyspieszyć GC z zerowaniem. Jestem pewien, że wolą nie martwić się o jak / kiedy GC prowadzi - traktować go tak wszechobecne Istota ochrony i czuwa nad i dla ciebie ... (łuki głową w dół, podnosi pięść do nieba) .. .
Osobiście często jawnie ustawiam zmienne na null, kiedy skończę z nimi jako formę samokontroli. Nie deklaruję, używam, a potem ustawiam na zero później - zeruję natychmiast po tym, gdy nie są już potrzebne. Mówię wprost: „Oficjalnie skończyłem z tobą ... odejdź ...”
Czy konieczne jest anulowanie w języku GC? Nie. Czy to jest pomocne dla GC? Może tak, może nie, nie wiem na pewno, z założenia naprawdę nie mogę tego kontrolować i niezależnie od dzisiejszej odpowiedzi z tą wersją, przyszłe implementacje GC mogą zmienić odpowiedź poza moją kontrolą. Plus, jeśli / kiedy zoptymalizowane jest zerowanie, to niewiele więcej niż fantazyjny komentarz, jeśli chcesz.
Sądzę, że jeśli dzięki temu moje zamiary staną się bardziej zrozumiałe dla następnego biednego głupca, który pójdzie w moje ślady, a jeśli to „może” czasem pomóc GC, to warto. Głównie sprawia, że czuję się schludnie i czysto, a Mongo lubi czuć się schludnie i czysto. :)
Patrzę na to w ten sposób: istnieją języki programowania, dzięki którym ludzie dają wyobrażenie o zamiarach i kompilatorowi zapytanie o zadanie do wykonania - kompilator konwertuje to żądanie na inny język (czasem kilka) dla procesora - procesor (y) może dać sygnał, jakiego języka użyłeś, ustawień twojej karty, komentarzy, akcentów stylistycznych, nazw zmiennych itp. - procesor dotyczy strumienia bitów, który informuje go o tym, jakie rejestry, kody operacyjne i lokalizacje pamięci mają się zmieniać. Wiele rzeczy napisanych w kodzie nie przekształca się w to, co zużywa CPU w podanej przez nas sekwencji. Nasz C, C ++, C #, Lisp, Babel, asembler lub cokolwiek to jest teoria, a nie rzeczywistość, napisane jako zestawienie pracy. To, co widzisz, nie jest tym, co dostajesz, nawet w języku asemblera.
Rozumiem, że sposób myślenia „niepotrzebnych rzeczy” (takich jak puste linie) „to nic innego jak szum i niepotrzebny kod”. To byłem ja wcześniej w mojej karierze; Całkowicie to rozumiem. W tym momencie pochylam się w kierunku tego, co czyni kod wyraźniejszym. To nie tak, że dodałem nawet 50 linii „szumu” do moich programów - to kilka linii tu czy tam.
Istnieją wyjątki od każdej reguły. W scenariuszach z pamięcią ulotną, pamięcią statyczną, warunkami wyścigu, singletonami, użyciem „przestarzałych” danych i tego rodzaju zgnilizny, to jest inne: POTRZEBUJESZ zarządzać własną pamięcią, blokować i unieważniać jako apropos, ponieważ pamięć nie jest częścią wszechświat GC'd - mam nadzieję, że wszyscy to rozumieją. Reszta czasu w językach GC to kwestia stylu, a nie konieczności lub gwarantowanego wzrostu wydajności.
Na koniec upewnij się, że rozumiesz, co kwalifikuje się do GC, a co nie; odpowiednio blokować, usuwać i unieważniać; woskować, woskować; wdech i wydech; i na wszystko inne mówię: jeśli to jest dobre, zrób to. Twój przebieg może się różnić ... tak jak powinien ...
źródło
Myślę, że przywrócenie wartości zerowej jest nieporządne. Wyobraź sobie scenariusz, w którym ustawiony jest teraz przedmiot, powiedzmy przez właściwość. Teraz jakoś fragment kodu przypadkowo wykorzystuje tę właściwość po usunięciu elementu, otrzymasz wyjątek o wartości zerowej, który wymaga dokładnego zbadania, co dokładnie się dzieje.
Wierzę, że jednorazowe ramy pozwolą na rzucenie ObjectDisposedException, co jest bardziej znaczące. Z tego powodu lepszym rozwiązaniem byłoby przywrócenie wartości zerowej.
źródło
Niektóre obiekty
.dispose()
zakładają metodę, która wymusza usunięcie zasobu z pamięci.źródło