Czy ktoś może mi wyjaśnić, dlaczego maszyny JVM (nie sprawdziłem ich zbyt wiele, ale nigdy nie widziałem takiego, który nie zrobiłby tego w ten sposób) muszą działać na stałym rozmiarze sterty? Wiem, że łatwiej jest wdrożyć na prostej, ciągłej sterty, ale Sun JVM ma już ponad dekadę, więc spodziewam się, że mieli czas, aby to poprawić.
Konieczność zdefiniowania maksymalnego rozmiaru pamięci programu podczas uruchamiania wydaje się być czymś w stylu lat 60., a potem są złe interakcje z zarządzaniem pamięcią wirtualną systemu operacyjnego (pobieranie GC zamieniło dane, niemożność ustalenia, ile pamięci jest proces Java naprawdę korzystający ze strony systemu operacyjnego, zmarnowane ogromne ilości miejsca na VM (wiem, że nie obchodzi cię twoje wymyślne 48-bitowe maszyny ...)). Sądzę również, że różne smutne próby budowy małych systemów operacyjnych w JVM (serwery aplikacji EE, OSGi) są przynajmniej częściowo winne za tę okoliczność, ponieważ uruchamianie wielu procesów Java w systemie niezmiennie prowadzi do zmarnowanych zasobów, ponieważ musisz daj każdemu z nich pamięć, której może potrzebować w szczycie.
Co zaskakujące, Google nie wywołało burzy oburzenia z powodu tego, czego się spodziewałem, ale mogły zostać pochowane pod milionami ludzi, którzy dowiadują się o ustalonej wielkości sterty i akceptują to.
Odpowiedzi:
Mylisz się. Rozmiar sterty maszyn JVM nie jest stały, a ograniczony:
Ustawienie górnej granicy jest konieczne z kilku powodów. Po pierwsze, informuje śmieciarza, kiedy ma zacząć działać. Po drugie, zapobiega zatykaniu się maszyny przez JVM przez zużywanie zbyt dużej ilości pamięci. Minimalna wielkość sterty jest prawdopodobnie przydatna do zarezerwowania takiej ilości pamięci, jakiej program potrzebuje, aby zapobiec wyczerpaniu się pamięci (ponieważ inne procesy zużywają zbyt dużo).
źródło
Wyobrażam sobie, że odpowiedź ma coś wspólnego z dziedzictwem Javy. Został pierwotnie zaprojektowany jako język używany w systemach wbudowanych, w których oczywiście zasoby są ograniczone i nie chcesz, aby procesy po prostu pochłaniały wszystko, co jest dostępne. Pomaga również w administrowaniu systemem, ponieważ ułatwia ustawienie zasobów na serwerze, jeśli można ustawić limity zasobów. Widzę, że najnowsze maszyny JVM wydają się używać wielu nieciągłych stert, chociaż oczywiście wszystko to pojawia się jako jedna sterty w kodzie.
(FWIW musiałeś określić wymagania dotyczące pamięci programu w wersjach MacOS sprzed Apple Darwina (i tak do wersji System 7, która była ostatnią, której używałem), która była już w latach 80.)
źródło
Musisz dać GC jakiś mechanizm, który poinformuje go, kiedy ma zostać uruchomiony, w przeciwnym razie twój program zapełni całą pamięć wirtualną. Istnieje wiele alternatywnych sposobów wyzwalania GC: upływający czas, liczba przydziałów, liczba przydziałów, prawdopodobnie inne, o których nie mogę teraz myśleć. IMO żaden z nich nie jest tak dobry, jak po prostu ustawienie granicy pamięci i uruchomienie GC, gdy przydzielone miejsce przekroczy tę granicę.
Kluczem jest ustawienie prawidłowych granic. Patrzę na
-ms
to: „tyle pamięci potrzebuje moja aplikacja” i-mx
„nigdy nie powinna przekraczać tej ilości”. W przypadku wdrożenia produkcyjnego oba powinny być blisko siebie, jeśli nie równe, i powinny być oparte na rzeczywistych, zmierzonych wymaganiach.Twoje obawy dotyczące „zmarnowanej” pamięci wirtualnej są bezpodstawne: jest wirtualna, (prawie) darmowa. Tak, nadanie stertom zbyt dużego przydziału oznacza, że nie można uruchomić tylu wątków ani załadować tylu plików mapowanych w pamięci. Ale to część projektowania aplikacji: masz ograniczone zasoby, musisz podzielić je na partycje w sposób umożliwiający uruchomienie aplikacji. W stosie „w stylu C”, który będzie się rozwijał, aż osiągniesz szczyt pamięci, podstawowy problem jest taki sam, po prostu nie musisz o tym myśleć, dopóki nie będziesz miał kłopotów.
Jedyną rzeczą, którą duża sterty może „zmarnować”, jest przestrzeń wymiany, ponieważ wszystkie zapisywalne segmenty wymagają zaangażowania wymiany. Ale to część projektowania systemu: jeśli chcesz mieć wiele JVM działających na tym samym urządzeniu, zwiększ swap lub zmniejsz przydział sterty. Jeśli zaczną szarpać, próbujesz zrobić zbyt wiele z systemem; kup więcej pamięci (a jeśli nadal korzystasz z procesora 32-bitowego, kup nowe pudełko).
źródło
Jak mówi user281377, określasz tylko górną granicę ilości pamięci, którą proces może zużyć. Oczywiście sama aplikacja zajmie tylko tyle miejsca, ile potrzebuje.
To, czy powinna istnieć domyślna górna granica, czy nie, to kolejne pytanie, zarówno z pro, jak i przeciw.
źródło