W twoim przykładzie myApple
ma specjalną wartość null
(zwykle wszystkie bity zerowe), a więc nie odnosi się do niczego. Obiekt, do którego pierwotnie się odnosił, został teraz utracony na stercie. Nie ma możliwości odzyskania jego lokalizacji. Jest to znane jako wyciek pamięci w systemach bez wyrzucania elementów bezużytecznych.
Jeśli pierwotnie ustawiłeś 1000 referencji na null, to masz miejsce tylko na 1000 referencji, zwykle 1000 * 4 bajtów (w systemie 32-bitowym, dwa razy więcej niż w 64). Jeśli te 1000 odniesień pierwotnie wskazywało na rzeczywiste obiekty, to przydzielono 1000 razy rozmiar każdego obiektu plus miejsce na 1000 odniesień.
W niektórych językach (takich jak C i C ++) wskaźniki zawsze wskazują na coś, nawet gdy są „niezainicjowane”. Problem polega na tym, czy adres, do którego prowadzą, jest legalny dla twojego programu. Specjalny adres zero (aka null
) celowo nie jest odwzorowywany w przestrzeni adresowej, więc jednostka zarządzania pamięcią (MMU) generuje błąd segmentacji, gdy jest uzyskiwany do niego dostęp i następuje awaria programu. Ale ponieważ adres zero celowo nie odwzorowywane, staje się wartością idealny do wykorzystania w celu wskazania, że wskaźnik nie jest skierowany do niczego, stąd swoją rolę null
. Aby ukończyć historię, alokując pamięć za pomocą new
lubmalloc()
, system operacyjny konfiguruje MMU do mapowania stron pamięci RAM w przestrzeni adresowej i stają się one użyteczne. Nadal istnieją zwykle duże zakresy przestrzeni adresowej, które nie są mapowane, a zatem prowadzą również do błędów segmentacji.
std::shared_ptr<Apple>
jest przykładem, który nie jest ani GC, ani nie przeciekaApple
po wyzerowaniu.shared_ptr
tylko podstawowa forma zbierania śmieci? GC nie wymaga oddzielnego „modułu wyrzucania elementów bezużytecznych”, tylko to, że ma miejsce wyrzucanie elementów bezużytecznych.Odpowiedź zależy od używanego języka.
C / C ++
W C i C ++ słowem kluczowym było NULL, a tak naprawdę NULL było 0. Zdecydowano, że „0x0000” nigdy nie będzie prawidłowym wskaźnikiem do obiektu, a więc taka wartość jest przypisywana w celu wskazania, że to nie jest prawidłowym wskaźnikiem. Jest to jednak całkowicie arbitralne. Jeśli spróbujesz uzyskać do niego dostęp jak wskaźnik, zachowa się on dokładnie tak jak wskaźnik do obiektu, którego już nie ma w pamięci, powodując zgłoszenie wyjątku nieprawidłowego wskaźnika. Sam wskaźnik zajmuje pamięć, ale nie więcej niż zwykły obiekt. Dlatego jeśli masz 1000 zerowych wskaźników, jest to odpowiednik 1000 liczb całkowitych. Jeśli niektóre z tych wskaźników wskazują na prawidłowe obiekty, wówczas użycie pamięci byłoby równoważne 1000 liczb całkowitych plus pamięć zawarta w tych prawidłowych wskaźnikach. Pamiętaj, że w C lub C ++,nie oznacza, że pamięć została zwolniona, więc musisz jawnie usunąć ten obiekt za pomocą dealloc (C) lub delete (C ++).
Jawa
W przeciwieństwie do C i C ++, w Javie null jest jedynie słowem kluczowym. Zamiast zarządzać wartością zerową jak wskaźnikiem do obiektu, jest on zarządzany wewnętrznie i traktowany jak literał. To wyeliminowało potrzebę wiązania wskaźników jako typów całkowitych i pozwala Javie całkowicie wyodrębnić wskaźniki. Jednak nawet jeśli Java lepiej to ukrywa, nadal są wskaźnikami, co oznacza, że 1000 wskaźników zerowych nadal zużywa równowartość 1000 liczb całkowitych. Oczywiście, gdy wskazują na obiekty, podobnie jak C i C ++, pamięć jest zużywana przez te obiekty, dopóki nie odwołują się do nich żadne wskaźniki, jednak w przeciwieństwie do C i C ++, śmieciarz zbiera je przy następnym przejściu i uwalnia pamięć, bez konieczności śledzenia, które obiekty są zwalniane, a które nie, w większości przypadków (chyba że masz powody, aby na przykład słabo odwoływać się do obiektów).
źródło
NULL
( nawiasem mówiąc, nie słowo kluczowe) są traktowane tak, jakby były zerowymi bitami. Ale nie muszą być realizowane jako takie, w rzeczywistości niektóre niejasne implementacje zrobić użytku niezerowe wskaźniki null. Jeśli napiszę,if (myptr == 0)
kompilator zrobi właściwą rzecz, nawet jeśli wskaźnik zerowy jest wewnętrznie reprezentowany przez0xabcdef
.0
jest stałą wskaźnika zerowego, ale nie oznacza to, żemyptr == 0
sprawdza, czy wszystkie bitymyptr
są równe zero.NULL
makrze, raczej mówiąc o „wskaźniku zerowym” i wyraźnie wspominając, że „literał-0 można niejawnie przekonwertować na wskaźnik zerowy”.Wskaźnik jest po prostu zmienną, która jest przeważnie liczbą całkowitą. Określa adres pamięci, w którym przechowywany jest rzeczywisty obiekt.
Większość języków pozwala na dostęp do elementów obiektu za pomocą tej zmiennej wskaźnika:
Kompilator wie, jak uzyskać dostęp do członków
Apple
. „Podąża” za wskaźnikiem domyApple
adresu i pobiera wartośćappleInt
Jeśli przypiszesz wskaźnik zerowy do zmiennej wskaźnika, ustawisz wskaźnik na brak adresu pamięci. (Co uniemożliwia dostęp do konta).
Dla każdego wskaźnika potrzebna jest pamięć do przechowywania wartości liczby całkowitej adresu pamięci (głównie 4 bajty w systemach 32-bitowych, 8 bajtów w systemach 64-bitowych). Dotyczy to również wskaźników zerowych.
źródło
Szybki przykład (nazwy zmiennych nie są przechowywane):
Twoje zdrowie.
źródło