AFAIK, specyfikacja JVM (napisana w języku angielskim) nie wspomina, kiedy dokładnie obiekt (lub wartość) powinna zostać usunięta, i pozostawia to do implementacji (podobnie dla R5RS ). W jakiś sposób wymaga lub sugeruje śmieciarz, ale pozostawia szczegóły do implementacji. Podobnie jest w przypadku specyfikacji Java.
Pamiętaj, że języki programowania to specyfikacje ( składni , semantyki itp.), A nie implementacje oprogramowania. Język taki jak Java (lub jego JVM) ma wiele implementacji. Jego specyfikacja jest opublikowana , dostępna do pobrania (abyś mógł ją przestudiować) i napisana w języku angielskim. §2.5.3 Sterta specyfikacji JVM wspomina o śmieciarzu:
Magazyn stosów dla obiektów jest odzyskiwany przez automatyczny system zarządzania pamięcią (znany jako kolektor śmieci); obiekty nigdy nie są jawnie zwolnione. Wirtualna maszyna Java nie zakłada żadnego konkretnego rodzaju automatycznego systemu zarządzania pamięcią masową
(nacisk jest mój; finalizacja BTW jest wspomniana w § 12.6 specyfikacji Java, a model pamięci znajduje się w §17.4 specyfikacji Java)
Tak więc (w Javie) nie powinieneś się przejmować, kiedy obiekt zostanie usunięty , i możesz kodować tak, jakby tak się nie stało (rozumując w abstrakcji, w której to ignorujesz). Oczywiście musisz dbać o zużycie pamięci i zestaw żywych przedmiotów, co jest innym pytaniem. W kilku prostych przypadkach (pomyśl o programie „witaj świecie”) jesteś w stanie udowodnić - lub przekonać siebie - że przydzielona pamięć jest raczej niewielka (np. Mniejsza niż gigabajt), a wtedy nie przejmujesz się wcale usuwanie poszczególnych obiektów. W wielu przypadkach możesz przekonać się, że żywe przedmioty(lub osiągalne, które są nadzbiorem - łatwiejszym do uzasadnienia - żywe) nigdy nie przekraczają rozsądnego limitu (a wtedy polegasz na GC, ale nie obchodzi cię, jak i kiedy ma miejsce wywóz śmieci). Przeczytaj o złożoności przestrzeni .
Wydaje mi się, że w kilku implementacjach JVM uruchamiających krótkotrwały program Java, taki jak program hello world, moduł wyrzucania elementów nie jest w ogóle uruchamiany i nie jest usuwany. AFAIU, takie zachowanie jest zgodne z licznymi specyfikacjami Java.
Większość implementacji JVM wykorzystuje generacyjne techniki kopiowania (przynajmniej dla większości obiektów Java, tych, które nie używają finalizacji lub słabych referencji ; finalizacja nie jest gwarantowana w krótkim czasie i może zostać odroczona, więc jest to po prostu przydatna funkcja, której Twój kod nie powinien zależą w dużej mierze od), w którym pojęcie usuwania pojedynczego obiektu nie ma żadnego sensu (ponieważ duży blok stref pamięci zawierających wiele obiektów - być może kilka megabajtów naraz zostaje zwolniony).
Gdyby specyfikacja JVM wymagała jak najszybszego usunięcia każdego obiektu (lub po prostu nałożyła więcej ograniczeń na usuwanie obiektów), skuteczne techniki generowania GC byłyby zabronione, a projektanci Java i JVM mądrze tego unikali.
BTW, możliwe, że naiwna maszyna JVM, która nigdy nie usuwa obiektów i nie zwalnia pamięci, może być zgodna ze specyfikacjami (literą, a nie duchem) i na pewno jest w stanie uruchomić cześć świata w praktyce (zauważ, że większość małe i krótkotrwałe programy Java prawdopodobnie nie przydzielają więcej niż kilka gigabajtów pamięci). Oczywiście taka JVM nie jest warta wzmianki i jest tylko zabawką (podobnie jak ta implementacja malloc
dla C). Zobacz Epsilon NoOp GC, aby uzyskać więcej. Rzeczywiste maszyny JVM są bardzo złożonymi programami i łączą kilka technik usuwania śmieci.
Ponadto Java nie jest tym samym, co JVM, i masz implementacje Java działające bez JVM (np. Wyprzedzające kompilatory Java, środowisko wykonawcze Android ). W niektórych przypadkach (głównie akademickich) możesz sobie wyobrazić (tak zwane techniki „usuwania śmieci” w czasie kompilacji), że program Java nie alokuje ani nie usuwa w czasie wykonywania (np. Ponieważ kompilator optymalizujący jest wystarczająco sprytny, aby używać tylko stos wywołań i zmienne automatyczne ).
Dlaczego obiekty Java nie są usuwane natychmiast po ich odwołaniu?
Ponieważ specyfikacje Java i JVM tego nie wymagają.
Więcej informacji znajdziesz w podręczniku GC (i specyfikacji JVM ). Zauważ, że bycie żywym (lub przydatnym do przyszłych obliczeń) dla obiektu jest właściwością całego programu (niemodularną).
Cel C preferuje podejście do zarządzania pamięcią z liczeniem referencji . Ma to również pułapki (np. Programista Objective-C musi dbać o referencje cykliczne , wyjaśniając słabe referencje, ale JVM dobrze radzi sobie z referencjami cyklicznymi w praktyce, bez konieczności zwracania uwagi przez programistę Java).
W programowaniu i projektowaniu języka programowania nie ma srebrnej kuli (należy pamiętać o problemie zatrzymania ; bycie użytecznym żywym przedmiotem jest ogólnie nierozstrzygalne ).
Możesz także przeczytać SICP , Pragmatics języka programowania , Dragon Book , Lisp In Small Pieces i systemy operacyjne: Three Easy Pieces . Nie dotyczą one Javy, ale otworzą ci umysł i powinny pomóc zrozumieć, co powinna zrobić JVM i jak może ona praktycznie działać (z innymi elementami) na twoim komputerze. Możesz również spędzić wiele miesięcy (lub kilka lat) na badaniu złożonego kodu źródłowego istniejących implementacji JVM typu open source (takich jak OpenJDK , który ma kilka milionów linii kodu źródłowego).