Wykorzystanie pamięci wirtualnej z Java w systemie Linux, za dużo pamięci

259

Mam problem z aplikacją Java działającą w systemie Linux.

Kiedy uruchamiam aplikację, używając domyślnego maksymalnego rozmiaru sterty (64 MB), widzę za pomocą aplikacji tops, że 240 MB pamięci wirtualnej jest przydzielonych do aplikacji. Powoduje to problemy z niektórymi innymi programami na komputerze, które są względnie ograniczone pod względem zasobów.

O ile rozumiem, zarezerwowana pamięć wirtualna i tak nie będzie używana, ponieważ kiedy osiągniemy limit sterty, OutOfMemoryErrorzostanie wyrzucona. Uruchomiłem tę samą aplikację w systemie Windows i widzę, że rozmiar pamięci wirtualnej i rozmiar sterty są podobne.

Czy w każdym razie mogę skonfigurować pamięć wirtualną używaną dla procesu Java w systemie Linux?

Edycja 1 : Problemem nie jest sterty. Problem polega na tym, że jeśli na przykład ustawię stos 128 MB, nadal Linux przydziela 210 MB pamięci wirtualnej, co nigdy nie jest potrzebne. **

Edycja 2 : Używanie ulimit -vpozwala ograniczyć ilość pamięci wirtualnej. Jeśli ustawiony rozmiar jest niższy niż 204 MB, aplikacja nie będzie działać, mimo że nie potrzebuje 204 MB, tylko 64 MB. Chcę więc zrozumieć, dlaczego Java wymaga tak dużej pamięci wirtualnej. Czy można to zmienić?

Edycja 3 : W systemie, który jest osadzony, działa kilka innych aplikacji. A system ma limit pamięci wirtualnej (od komentarzy, ważnych szczegółów).

Mario Ortegón
źródło
Dlaczego martwisz się wykorzystaniem pamięci wirtualnej? Jeśli naprawdę chcesz się tym przejmować, sprawdź użycie pamięci rezydentnej i przeczytaj następujące polecenia: free, ps, top.
basszero
2
W systemie, który jest osadzony, działa kilka innych aplikacji. A system ma limit pamięci wirtualnej.
Mario Ortegón,
ahhhh, diabeł tkwi w szczegółach
basszero
Jakiej implementacji Java używasz. IIRC, standardowe środowisko Sun JRE dla torfowiska (inne niż OpenJDK) nie jest licencjonowane do wbudowania.
Tom Hawtin - tackline
Chyba nie wykorzystałem części „osadzonej” ... ma ona ograniczoną pamięć i sprzęt jest dostosowany, ale wciąż jest to standardowy komputer
Mario Ortegón,

Odpowiedzi:

630

Jest to od dawna skarga na Javę, ale jest w dużej mierze bez znaczenia i zwykle opiera się na spojrzeniu na niewłaściwe informacje. Zwykłe frazowanie to coś w stylu „Hello World na Javie zajmuje 10 megabajtów! Dlaczego to potrzebne?” Oto sposób, aby Hello World na 64-bitowej maszynie JVM przejął 4 gigabajty ... przynajmniej przez jedną formę pomiaru.

java -Xms1024m -Xmx4096m com.example.Hello

Różne sposoby pomiaru pamięci

W systemie Linux górne polecenie podaje kilka różnych liczb pamięci. Oto, co mówi o przykładzie Hello World:

  PID USER PR NI VIRT RES SHR S% CPU% MEM TIME + COMMAND
 2120 kgregory 20 0 4373m 15m 7152 S 0 0,2 0: 00,10 java
  • VIRT to przestrzeń pamięci wirtualnej: suma wszystkiego na mapie pamięci wirtualnej (patrz poniżej). Jest w dużej mierze bez znaczenia, z wyjątkiem sytuacji, gdy nie jest (patrz poniżej).
  • RES jest rezydentnym rozmiarem zestawu: liczbą stron, które są obecnie rezydentem w pamięci RAM. W prawie wszystkich przypadkach jest to jedyna liczba, której należy użyć, mówiąc „za duży”. Ale wciąż nie jest to zbyt dobra liczba, szczególnie jeśli chodzi o Javę.
  • SHR to ilość rezydentnej pamięci współdzielonej z innymi procesami. W przypadku procesu Java jest to zwykle ograniczone do bibliotek współdzielonych i plików JAR zamapowanych w pamięci. W tym przykładzie działał tylko jeden proces Java, więc podejrzewam, że 7k jest wynikiem bibliotek używanych przez system operacyjny.
  • SWAP nie jest domyślnie włączony i nie jest tu pokazywany. Wskazuje ilość pamięci wirtualnej aktualnie rezydującej na dysku, niezależnie od tego , czy faktycznie znajduje się w przestrzeni wymiany . System operacyjny bardzo dobrze trzyma aktywne strony w pamięci RAM, a jedynym sposobem na zamianę jest (1) zakup większej ilości pamięci lub (2) zmniejszenie liczby procesów, więc najlepiej zignorować tę liczbę.

Sytuacja Menedżera zadań Windows jest nieco bardziej skomplikowana. W systemie Windows XP są kolumny „Wykorzystanie pamięci” i „Rozmiar pamięci wirtualnej”, ale oficjalna dokumentacja milczy na ich temat. Windows Vista i Windows 7 dodają więcej kolumn i są one faktycznie udokumentowane . Spośród nich najbardziej użyteczny jest pomiar „zestawu roboczego”; w przybliżeniu odpowiada sumie RES i SHR w systemie Linux.

Zrozumienie wirtualnej mapy pamięci

Pamięć wirtualna zużywana przez proces jest sumą wszystkiego, co znajduje się na mapie pamięci procesu. Obejmuje to dane (np. Stertę Java), ale także wszystkie biblioteki współdzielone i pliki mapowane w pamięci używane przez program. W systemie Linux możesz użyć polecenia pmap, aby zobaczyć wszystkie rzeczy zmapowane w przestrzeni procesu (od tej pory będę odnosił się tylko do Linuksa, ponieważ tego właśnie używam; jestem pewien, że istnieją równoważne narzędzia do Windows). Oto fragment mapy pamięci programu „Hello World”; cała mapa pamięci ma ponad 100 linii i nie jest niczym niezwykłym posiadanie listy tysiąca linii.

0000000040000000 36K rx-- /usr/local/java/jdk-1.6-x64/bin/java
0000000040108000 8K rwx-- /usr/local/java/jdk-1.6-x64/bin/java
0000000040eba000 676K rwx-- [anon]
00000006fae00000 21248K rwx-- [anon]
00000006fc2c0000 62720K rwx-- [anon]
0000000700000000 699072K rwx-- [anon]
000000072aab0000 2097152K rwx-- [anon]
00000007aaab0000 349504K rwx-- [anon]
00000007c0000000 1048576K rwx-- [anon]
...
00007fa1ed00d000 1652K r-xs- /usr/local/java/jdk-1.6-x64/jre/lib/rt.jar
...
00007fa1ed1d3000 1024K rwx-- [anon]
00007fa1ed2d3000 4K ----- [anon]
00007fa1ed2d4000 1024K rwx-- [anon]
00007fa1ed3d4000 4K ----- [anon]
...
00007fa1f20d3000 164K rx-- /usr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so
00007fa1f20fc000 1020K ----- /usr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so
00007fa1f21fb000 28K rwx-- /usr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so
...
00007fa1f34aa000 1576K rx-- /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3634000 2044K ----- /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3833000 16K rx-- /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3837000 4K rwx-- /lib/x86_64-linux-gnu/libc-2.13.so
...

Szybkie wyjaśnienie formatu: każdy wiersz zaczyna się od adresu pamięci wirtualnej segmentu. Po tym następuje rozmiar segmentu, uprawnienia i źródło segmentu. Ten ostatni element to albo plik, albo „anon”, co oznacza blok pamięci przydzielany przez mmap .

Zaczynając od góry, mamy

  • Moduł ładujący JVM (tzn. Program uruchamiany podczas pisania java). To jest bardzo małe; wszystko, co robi, to ładowanie do bibliotek współdzielonych, w których przechowywany jest prawdziwy kod JVM.
  • Kilka bloków anonowych zawierających stos Javy i dane wewnętrzne. Jest to Sun JVM, więc sterta jest podzielona na wiele generacji, z których każda jest własnym blokiem pamięci. Zauważ, że JVM przydziela przestrzeń pamięci wirtualnej na podstawie -Xmxwartości; pozwala to mieć ciągłą stertę. Ta -Xmswartość jest używana wewnętrznie do określenia, ile sterty jest „w użyciu” podczas uruchamiania programu, oraz do wyzwalania wyrzucania elementów bezużytecznych w miarę zbliżania się tego limitu.
  • Plik JAR odwzorowany w pamięci, w tym przypadku plik zawierający „klasy JDK”. Kiedy mapujesz pamięć JAR, możesz bardzo wydajnie uzyskiwać dostęp do plików w nim zawartych (w porównaniu z odczytywaniem go od początku za każdym razem). Sun JVM zmapuje w pamięci wszystkie pliki JAR w ścieżce klasy; jeśli twój kod aplikacji musi uzyskać dostęp do pliku JAR, możesz go również zmapować w pamięci.
  • Dane dla wątku dla dwóch wątków. Blok 1M to stos wątków. Nie miałem dobrego wyjaśnienia dla bloku 4k, ale @ericsoe zidentyfikował go jako „blok ochronny”: nie ma uprawnień do odczytu / zapisu, więc spowoduje błąd segmentu, jeśli zostanie uzyskany dostęp, a JVM złapie to i tłumaczy to do StackOverFlowError. W przypadku prawdziwej aplikacji zobaczysz dziesiątki, jeśli nie setki tych wpisów powtórzonych przez mapę pamięci.
  • Jedna z bibliotek współdzielonych, która przechowuje aktualny kod JVM. Jest ich kilka.
  • Biblioteka współdzielona dla biblioteki standardowej C. To tylko jedna z wielu rzeczy, które ładuje JVM, które nie są ściśle częścią Javy.

Współużytkowane biblioteki są szczególnie interesujące: każda wspólna biblioteka ma co najmniej dwa segmenty: segment tylko do odczytu zawierający kod biblioteki oraz segment do odczytu i zapisu, który zawiera globalne dane dla poszczególnych procesów dla biblioteki (nie wiem, co segment bez uprawnień to; Widziałem go tylko na Linuksie x64). Część biblioteki tylko do odczytu może być współużytkowana przez wszystkie procesy korzystające z biblioteki; na przykład libcma 1,5 mln pamięci wirtualnej, którą można współdzielić.

Kiedy rozmiar pamięci wirtualnej jest ważny?

Mapa pamięci wirtualnej zawiera wiele rzeczy. Niektóre z nich są tylko do odczytu, niektóre są udostępniane, a niektóre są przydzielane, ale nigdy nie zostały zmienione (np. Prawie wszystkie 4 Gb stosu w tym przykładzie). Ale system operacyjny jest wystarczająco inteligentny, aby załadować tylko to, czego potrzebuje, więc rozmiar pamięci wirtualnej jest w dużej mierze nieistotny.

Ważna jest wielkość pamięci wirtualnej, jeśli używasz 32-bitowego systemu operacyjnego, w którym możesz przydzielić tylko 2 Gb (lub, w niektórych przypadkach, 3Gb) przestrzeni adresowej procesu. W takim przypadku masz do czynienia z ograniczonym zasobem i być może będziesz musiał dokonać kompromisów, takich jak zmniejszenie wielkości sterty w celu mapowania pamięci dużego pliku lub utworzenia wielu wątków.

Ale biorąc pod uwagę, że 64-bitowe maszyny są wszechobecne, nie sądzę, że minie dużo czasu, zanim Rozmiar pamięci wirtualnej stanie się zupełnie nieistotną statystyką.

Kiedy Resident Set Size jest ważny?

Rozmiar zestawu rezydentnego to część przestrzeni pamięci wirtualnej, która faktycznie znajduje się w pamięci RAM. Jeśli Twój RSS staje się znaczną częścią całkowitej pamięci fizycznej, być może nadszedł czas, aby zacząć się martwić. Jeśli Twój RSS rośnie i zajmuje całą twoją pamięć fizyczną, a twój system zaczyna się zamieniać, nadszedł czas, aby zacząć się martwić.

Ale RSS również wprowadza w błąd, szczególnie na lekko obciążonej maszynie. System operacyjny nie wymaga wiele wysiłku, aby odzyskać strony używane przez proces. Dzięki temu nie zyskasz zbyt wiele, a możliwość wystąpienia kosztownej usterki strony, jeśli proces dotknie strony w przyszłości. W rezultacie statystyki RSS mogą obejmować wiele stron, które nie są aktywnie używane.

Dolna linia

O ile nie dokonujesz wymiany, nie przejmuj się zbytnio tym, co mówią różne statystyki pamięci. Z zastrzeżeniem, że stale rosnący RSS może wskazywać na pewien wyciek pamięci.

W programie Java znacznie ważniejsze jest zwrócenie uwagi na to, co dzieje się na stosie. Ważna jest łączna ilość zajętego miejsca i można podjąć pewne kroki, aby ją zmniejszyć. Ważniejsze jest to, ile czasu spędzasz na zbieraniu śmieci i jakie części sterty są zbierane.

Dostęp do dysku (tj. Bazy danych) jest drogi, a pamięć tania. Jeśli możesz wymienić jeden na drugi, zrób to.

kdgregory
źródło
9
Należy wziąć pod uwagę, że w wymianie OZE brakuje części pamięci, które są obecnie zamienione. Być może masz niską wartość RES, ale tylko dlatego, że aplikacja była nieaktywna, a duża część sterty została zamieniona na dysk. Java wykonuje bardzo złą pracę wrt do zamiany: na każdym pełnym GC większość sterty jest przenoszona i kopiowana, więc jeśli znaczna część sterty była zamieniona, GC musi załadować wszystko z powrotem do pamięci głównej.
jrudolph
1
Świetna odpowiedź kdgregory! Pracuję w środowisku osadzonym za pomocą systemu CF, który nie ma przestrzeni wymiany. Więc na podstawie twojej odpowiedzi wszystkie moje wartości VIRT, SWAP i nFLT pochodzą z plików mapowanych w pamięci ... co teraz ma sens wycinaniu. Czy wiesz, czy wartość SWAP reprezentuje strony, które nie zostały jeszcze załadowane do pamięci lub strony, które zostały zamienione z pamięci, czy obie? Jak możemy uzyskać pojęcie o możliwym thrashingu (ciągła mapa, a następnie zamiana)?
Jeach
2
@Jeach - Byłem zaskoczony, że zgłoszono jakąkolwiek zamianę, więc uruchomiłem mojego „podróżującego Linuksa” (pendrive z Ubuntu 10.04 i brak zamiany). Kiedy włączyłem kolumnę „SWAP” u góry , zobaczyłem, że Eclipse ma 509 m. Kiedy wtedy spojrzałem na to z pmap , całkowita wirtualna przestrzeń wynosiła 650m. Podejrzewam więc, że liczba „SWAP” reprezentuje wszystkie strony na dysku, a nie tylko te, których nie ma w pamięci.
kdgregory
2
Jeśli chodzi o drugie pytanie: jeśli ciągle czytasz strony z karty flash, czas oczekiwania na IO (pokazany w podsumowaniu góry jako „% wa”) powinien być wysoki. Uważaj jednak, że będzie to wysoki poziom dla każdej aktywności, szczególnie pisze (zakładając, że twój program to robi).
kdgregory
1
> Blok 1M to stos wątków; Nie wiem, co wchodzi w blok 4K. Blok 4K - oznaczony jako nieposiadający uprawnień do odczytu ani zapisu - jest prawdopodobnie blokiem ochronnym. W przypadku przepełnienia stosu dostęp do tego obszaru jest wywoływany, co powoduje błąd, który JVM może następnie obsłużyć, generując wyjątek Java StackOverflowException. Jest to o wiele tańsze niż sprawdzanie wskaźnika stosu przy każdym wywołaniu metody. Obszary ochrony bez ustawionych uprawnień można również zobaczyć w innych kontekstach.
eriksoe
38

Znany jest problem z Javą i glibc> = 2.10 (obejmuje Ubuntu> = 10.04, RHEL> = 6).

Lekarstwem jest ustawienie tego środowiska. zmienna:

export MALLOC_ARENA_MAX=4

Jeśli korzystasz z Tomcat, możesz dodać to do TOMCAT_HOME/bin/setenv.shpliku.

W przypadku Docker dodaj to do Dockerfile

ENV MALLOC_ARENA_MAX=4

Istnieje artykuł IBM na temat ustawiania MALLOC_ARENA_MAX https://www.ibm.com/developerworks/community/blogs/kevgrig/entry/linux_glibc_2_10_rhel_6_malloc_may_show_excessive_virtual_memory_usage?lang=en

Ten post na blogu mówi

pamięć rezydentna znana jest z pełzania w sposób podobny do wycieku pamięci lub fragmentacji pamięci.

Istnieje również otwarty błąd JDK JDK-8193521 „glibc marnuje pamięć przy domyślnej konfiguracji”

wyszukaj MALLOC_ARENA_MAX w Google lub SO, aby uzyskać więcej referencji.

Możesz także dostroić inne opcje malloc, aby zoptymalizować pod kątem małej fragmentacji przydzielonej pamięci:

# tune glibc memory allocation, optimize for low fragmentation
# limit the number of arenas
export MALLOC_ARENA_MAX=2
# disable dynamic mmap threshold, see M_MMAP_THRESHOLD in "man mallopt"
export MALLOC_MMAP_THRESHOLD_=131072
export MALLOC_TRIM_THRESHOLD_=131072
export MALLOC_TOP_PAD_=131072
export MALLOC_MMAP_MAX_=65536
Lari Hotari
źródło
Ta odpowiedź naprawdę pomogła mi na 64-bitowym serwerze Ubuntu z serwerem TomEE, który ma małe możliwości do „zużycia pamięci”. Link do artykułu IBM naprawdę jest głębokim wyjaśnieniem. Jeszcze raz dziękuję za tę dobrą wskazówkę!
MWiesner
1
JVM może wyciec natywną pamięć, co prowadzi do podobnych objawów. Zobacz stackoverflow.com/a/35610063/166062 . Nieszczelne instancje GZIPInputStream i GZIPOutputStream również mogą być źródłem wycieku.
Lari Hotari,
3
W Javie 8 występuje błąd JVM, który powoduje nieograniczony wzrost pamięci natywnej: bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8164293 - Jeśli wpływa to na ciebie, użycie MALLOC_ARENA_MAXmoże spowolnić wzrost pamięci, ale nie rozwiązać problem całkowicie.
outofcoffee
@LariHotari naprawdę docenia twój wysiłek, aby wskazać wersję glibc i redhat
Sam
2
Java 8u131 zawiera cofniętą poprawkę dla powiązanego błędu JVM JDK-8164293 bugs.openjdk.java.net/browse/JDK-8178124 .
Lari Hotari,
9

Ilość pamięci przydzielonej na proces Java jest prawie taka sama, jak się spodziewałbym. Miałem podobne problemy z uruchomieniem Javy w systemach osadzonych / z ograniczoną pamięcią. Uruchamianie dowolnej aplikacji z dowolnymi limitami maszyn wirtualnych lub w systemach, które nie mają wystarczającej ilości zamiany, zwykle się psują. Wydaje się, że taka jest natura wielu nowoczesnych aplikacji, które nie są przeznaczone do użytku w systemach o ograniczonych zasobach.

Masz jeszcze kilka opcji, które możesz spróbować ograniczyć w pamięci JVM. Może to zmniejszyć zużycie pamięci wirtualnej:

-XX: ReservedCodeCacheSize = 32m Zarezerwowany rozmiar pamięci podręcznej kodu (w bajtach) - maksymalny rozmiar pamięci podręcznej kodu. [Solaris 64-bit, amd64 i -server x86: 48m; w wersji 1.5.0_06 i wcześniejszych, Solaris 64-bitowy i 64: 1024m.]

-XX: MaxPermSize = 64m Rozmiar stałej generacji. [5.0 i nowsze: 64-bitowe maszyny wirtualne są skalowane o 30%; 1,4 am64: 96 m; 1.3.1 -klient: 32m.]

Ponadto należy również ustawić wartość -Xmx (maksymalny rozmiar sterty) na wartość możliwie zbliżoną do rzeczywistego szczytowego wykorzystania pamięci przez aplikację. Wierzę, że domyślne zachowanie JVM wciąż podwaja wielkość sterty za każdym razem, gdy rozszerza ją do maksimum. Jeśli zaczniesz od stosu 32 mln, a Twoja aplikacja osiągnie maksymalny poziom 65 mln, wówczas stos zwiększy się do 32 mln -> 64 mln -> 128 mln.

Możesz także spróbować to zrobić, aby maszyna wirtualna była mniej agresywna w kwestii powiększania stosu:

-XX: MinHeapFreeRatio = 40 Minimalny procent wolnej sterty po GC, aby uniknąć ekspansji.

Ponadto, z tego, co pamiętam z eksperymentowania z tym kilka lat temu, liczba załadowanych bibliotek natywnych miała ogromny wpływ na minimalny rozmiar. Ładowanie java.net.Socket dodał więcej niż 15 mln, jeśli dobrze pamiętam (i prawdopodobnie nie).

James Schek
źródło
7

Sun JVM wymaga dużo pamięci dla HotSpot i mapuje w bibliotekach wykonawczych we wspólnej pamięci.

Jeśli problem dotyczy pamięci, rozważ użycie innej maszyny JVM odpowiedniej do osadzania. IBM ma wersję j9 i istnieje „jamvm” Open Source, który korzysta z bibliotek ścieżek klas GNU. Również Sun ma Squeak JVM działający na SunSPOTS, więc istnieją alternatywy.

Thorbjørn Ravn Andersen
źródło
Czy można wyłączyć hot spot?
Mario Ortegón,
Być może. Sprawdź opcje wiersza polecenia dla używanej maszyny JVM.
Thorbjørn Ravn Andersen
3

Po prostu myślałem, ale można sprawdzić wpływ na ulimit -vopcję .

To nie jest rzeczywiste rozwiązanie, ponieważ ograniczyłoby przestrzeń adresową dostępną dla całego procesu, ale pozwoliłoby to sprawdzić zachowanie aplikacji przy ograniczonej pamięci wirtualnej.

VonC
źródło
To jest dokładnie mój problem. My Heap jest ustawiony na 64 mln, ale Linux rezerwuje 204 MB. Jeśli ustawię ulimit poniżej 204, aplikacja w ogóle nie będzie działać.
Mario Ortegón,
Interesujące: ustawienie ulimit może mieć niezamierzony efekt uboczny dla innych procesów, wyjaśniając, dlaczego aplikacja nie jest w stanie uruchomić.
VonC
Problem polega na tym, że Java wymaga zarezerwowania większej ilości pamięci wirtualnej, nawet jeśli jej nie wykorzysta. W systemie Windows używana pamięć wirtualna i ustawienie Xmx są raczej bliżej.
Mario Ortegón,
Czy wypróbowałeś to z JRockit JVM?
VonC
Ponieważ alokacja pamięci JVM jest sumą alokacji sterty i wielkości permu (pierwszą można ustalić za pomocą opcji -Xms i -Xmx), czy wypróbowałeś niektóre ustawienia z opcją -XX: PermSize i -XX: MaxPermSize (domyślnie od 32 MB do 64 MB w zależności od wersji JVM)?
VCC
3

Jednym ze sposobów zmniejszenia rozmiaru stosu w systemie o ograniczonych zasobach może być zabawa ze zmienną -XX: MaxHeapFreeRatio. Zazwyczaj jest to 70 i jest to maksymalny procent sterty, która jest wolna, zanim GC ją zmniejszy. Ustawienie go na niższą wartość, a zobaczysz np. W profilu jvisualvm, że w twoim programie zwykle używana jest mniejsza liczba kupek.

EDYCJA: Aby ustawić małe wartości dla -XX: MaxHeapFreeRatio, musisz również ustawić -XX: MinHeapFreeRatio np.

java -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=25 HelloWorld

EDYCJA 2: Dodano przykład prawdziwej aplikacji, która uruchamia się i wykonuje to samo zadanie, jedno z parametrami domyślnymi, a drugie z parametrami 10 i 25. Nie zauważyłem żadnej rzeczywistej różnicy prędkości, chociaż java teoretycznie powinna poświęcić więcej czasu na zwiększenie stosu w drugim przykładzie.

Parametry domyślne

Na koniec maksymalna sterta to 905, używana sterta to 378

MinHeap 10, MaxHeap 25

Na koniec maksymalna sterta to 722, używana sterta to 378

To faktycznie ma pewien niedokładny charakter, ponieważ nasza aplikacja działa na serwerze zdalnego pulpitu i wielu użytkowników może ją uruchomić jednocześnie.

runholen
źródło
1

Java 1.4 firmy Sun ma następujące argumenty do kontrolowania wielkości pamięci:

-Xmsn Podaj początkowy rozmiar puli alokacji pamięci (w bajtach). Ta wartość musi być wielokrotnością 1024 większą niż 1 MB. Dołącz literę k lub K, aby wskazać kilobajty, lub m lub M, aby wskazać megabajty. Wartość domyślna to 2 MB. Przykłady:

           -Xms6291456
           -Xms6144k
           -Xms6m

-Xmxn Podaj maksymalny rozmiar puli alokacji pamięci (w bajtach). Ta wartość musi być wielokrotnością 1024 większą niż 2 MB. Dołącz literę k lub K, aby wskazać kilobajty, lub m lub M, aby wskazać megabajty. Wartość domyślna to 64 MB. Przykłady:

           -Xmx83886080
           -Xmx81920k
           -Xmx80m

http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/java.html

Java 5 i 6 mają trochę więcej. Zobacz http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

Paul Tomblin
źródło
1
Problem, który mam, nie dotyczy wielkości sterty, ale ilości pamięci wirtualnej przypisywanej przez system Linux
Mario Ortegón,
Przeczytaj wyjaśnienie kdgregory. Zmniejszenie wielkości sterty, „Nowy rozmiar” i inne konfigurowalne parametry zmniejszą ilość PRAWDZIWEJ pamięci zajmowanej przez Jvm.
Paul Tomblin
Może mieć uzasadniony problem. Niektóre aplikacje (jak jeden napisałem) mapują plik 1 GB, a niektóre systemy mają tylko 2 GB pamięci wirtualnej, a niektóre z nich są zapełniane bibliotekami współdzielonymi. A jeśli to jest problem, powinien zdecydowanie wyłączyć randomizację DSO. Istnieje opcja w / proc.
Zan Lynx,
0

Nie, nie możesz skonfigurować ilości pamięci wymaganej przez VM. Należy jednak pamiętać, że jest to pamięć wirtualna, nie rezydentna, więc pozostaje tam bez szkody, jeśli nie jest faktycznie używana.

Alternatywnie możesz wypróbować inną maszynę JVM niż Sun, o mniejszej pojemności pamięci, ale nie mogę tu doradzić.

Marko
źródło