Správa paměti v Javě
Poznámka:
Plány Basic, Standard a Enterprise budou od poloviny března 2025 vyřazeny ze 3letého období vyřazení. Doporučujeme přejít na Azure Container Apps. Další informace najdete v oznámení o vyřazení Azure Spring Apps.
Od 30. září 2024 bude od 30. září 2024 zastaralý plán s úplným vypnutím po šesti měsících. Doporučujeme přejít na Azure Container Apps. Další informace najdete v tématu Migrace spotřeby Azure Spring Apps Úrovně Standard a vyhrazeného plánu do Azure Container Apps.
Tento článek se vztahuje na:✅ Basic/Standard ❎ Enterprise
Tento článek popisuje různé koncepty související se správou paměti Java, které vám pomůžou pochopit chování aplikací v Javě hostovaných v Azure Spring Apps.
Model paměti Java
Paměť aplikace v Javě má několik částí a existují různé způsoby rozdělení částí. Tento článek popisuje paměť Javy rozdělenou do paměti haldy, paměti bez haldy a přímé paměti.
Paměť haldy
Paměť haldy ukládá všechny instance a pole tříd. Každý virtuální počítač Java (JVM) má pouze jednu oblast haldy, která se sdílí mezi vlákny.
Ovladač Spring Boot může sledovat hodnotu paměti haldy. Spring Boot Poháněcího zařízení přebírá hodnotu haldy jako součást jvm.memory.used/committed/max
. Další informace najdete v části jvm.memory.used/committed/max v nástrojích pro řešení problémů s pamětí.
Paměť haldy je rozdělena na mladou generaci a starou generaci. Tyto termíny jsou popsány v následujícím seznamu spolu se souvisejícími termíny.
Mladá generace: všechny nové objekty jsou přiděleny a ve věku mladé generace.
- Eden prostor: nové objekty jsou přiděleny v Eden prostoru.
- Přeživší prostor: objekty se přesunou z Edenu do prostoru přeživšího po přežití jednoho cyklu uvolňování paměti. Přeživší prostor lze rozdělit na dvě části: s1 a s2.
Stará generace: označuje se také jako tenured prostor. Objekty, které zůstaly v přeživších prostorech po dlouhou dobu, budou přesunuty do staré generace.
Před Javou 8 byla také součástí haldy další oddíl s názvem trvalé generování . Od Javy 8 se trvalé generování nahradilo metaprostorem v paměti bez haldy.
Paměť bez haldy
Paměť bez haldy je rozdělena do následujících částí:
Část paměti bez haldy, která nahradila trvalou generaci (nebo permGen) počínaje Javou 8. Spring Boot Poháněcí zařízení sleduje tuto část a bere ji jako součást
jvm.memory.used/committed/max
. Jinými slovy,jvm.memory.used/committed/max
je součet paměti haldy a bývalý permGen část paměti bez haldy. Bývalá trvalá generace se skládá z následujících částí:- Metaspace, který ukládá definice tříd načtené zavaděči tříd.
- Komprimovaný prostor třídy, který je určen pro komprimované ukazatele třídy.
- Mezipaměť kódu, která ukládá nativní kód zkompilovaný JIT.
Jiná paměť, jako je zásobník vláken, který není pozorován pomocí ovladače Spring Boot.
Přímá paměť
Přímá paměť je nativní paměť přidělena java.nio.DirectByteBuffer
, která se používá v knihovnách třetích stran, jako je nio a gzip.
Poháněcího zařízení Spring Boot není pozorována hodnota přímé paměti.
Následující diagram shrnuje model paměti Java popsaný v předchozí části.
Uvolňování paměti Jazyka Java
Existují tři termíny týkající se uvolňování paměti Java (GC): "Minor GC", "Major GC" a "Full GC". Tyto termíny nejsou jasně definovány ve specifikaci prostředí JVM. Tady považujeme za ekvivalentní hlavní uvolňování paměti a úplné uvolňování paměti.
Menší uvolňování paměti se provádí, když je eden prostor plný. Odstraní všechny mrtvé objekty v mladé generaci a přesune živé objekty z Eden prostoru do s1 přeživšího prostoru nebo od s1 do s2.
Úplné uvolňování paměti nebo hlavní uvolňování paměti v celé haldě. Full GC může také shromažďovat části, jako je metaprostor a přímá paměť, které lze vyčistit pouze úplným uvolňováním paměti.
Maximální velikost haldy ovlivňuje frekvenci menšího uvolňování paměti a plného uvolňování paměti. Maximální metaprostor a maximální velikost přímé paměti ovlivňují plné uvolňování paměti.
Když nastavíte maximální velikost haldy na nižší hodnotu, dochází k uvolňování paměti častěji, což aplikaci trochu zpomaluje, ale lépe omezuje využití paměti. Když nastavíte maximální velikost haldy na vyšší hodnotu, dochází k uvolňování paměti méně často, což může způsobit větší riziko nedostatku paměti (OOM). Další informace najdete v části Typy problémů s nedostatkem paměti při restartování aplikace způsobené problémy s nedostatkem paměti.
Metaprostor a přímá paměť lze shromažďovat pouze úplným uvolňováním paměti. Pokud je metaprostor nebo přímá paměť plná, dojde k úplnému uvolňování paměti.
Konfigurace paměti Java
Následující části popisují důležité aspekty konfigurace paměti Java.
Kontejnerizace Java
Aplikace v Azure Spring Apps běží v kontejnerových prostředích. Další informace najdete v tématu Kontejnerizace aplikací v Javě.
Důležité možnosti prostředí JVM
Maximální velikost každé části paměti můžete nakonfigurovat pomocí možností prostředí JVM. Možnosti prostředí JVM můžete nastavit pomocí příkazů Azure CLI nebo webu Azure Portal. Další informace najdete v části Upravit konfigurace a opravit problémy nástroje pro řešení problémů s pamětí.
Následující seznam popisuje možnosti prostředí JVM:
Konfigurace velikosti haldy
-Xms
nastaví počáteční velikost haldy absolutní hodnotou.-Xmx
nastaví maximální velikost haldy absolutní hodnotou.-XX:InitialRAMPercentage
nastaví počáteční velikost haldy o procento velikosti haldy / velikosti paměti aplikace.-XX:MaxRAMPercentage
nastaví maximální velikost haldy o procento velikosti haldy nebo velikosti paměti aplikace.
Konfigurace přímé velikosti paměti
-XX:MaxDirectMemorySize
nastaví maximální velikost přímé paměti absolutní hodnotou. Další informace naleznete v tématu MaxDirectMemorySize v dokumentaci Oracle.
Konfigurace velikosti metaprostoru
-XX:MaxMetaspaceSize
nastaví maximální velikost metaprostoru absolutní hodnotou.
Výchozí maximální velikost paměti
Následující části popisují, jak jsou nastaveny výchozí maximální velikosti paměti.
Výchozí maximální velikost haldy
Azure Spring Apps nastaví výchozí maximální velikost paměti haldy na přibližně 50 –80 % paměti aplikace pro aplikace v Javě. Konkrétně Azure Spring Apps používá následující nastavení:
- Pokud paměť < aplikace 1 GB, bude výchozí maximální velikost haldy 50 % paměti aplikace.
- Pokud 1 GB <= paměť < aplikace 2 GB, bude výchozí maximální velikost haldy 60 % paměti aplikace.
- Pokud 2 GB <= paměť < aplikace 3 GB, výchozí maximální velikost haldy bude 70 % paměti aplikace.
- Pokud 3 GB <= paměť aplikace, výchozí maximální velikost haldy bude 80 % paměti aplikace.
Výchozí maximální velikost přímé paměti
Pokud maximální velikost přímé paměti není nastavena pomocí možností JVM, JVM automaticky nastaví maximální přímou velikost paměti na hodnotu vrácenou modulem Runtime.getRuntime.maxMemory(). Tato hodnota se přibližně rovná maximální velikosti paměti haldy. Další informace naleznete v souboru JDK 8 VM.java.
Rozložení využití paměti
Velikost haldy má vliv na propustnost. V podstatě při konfiguraci můžete zachovat výchozí maximální velikost haldy, která ponechá přiměřenou paměť pro jiné části.
Velikost metaprostoru závisí na složitosti kódu, například počtu tříd.
Velikost přímé paměti závisí na propustnosti a použití knihoven třetích stran, jako je nio a gzip.
Následující seznam popisuje typickou ukázku rozložení paměti pro 2 GB aplikací. V tomto seznamu můžete nakonfigurovat nastavení velikosti paměti.
- Celková paměť (2048 M)
- Paměť haldy: Xmx je 1433,6M (70 % celkové paměti). Referenční hodnota denního využití paměti je 1200 M.
- Dorost
- Přeživší prostor (S0, S1)
- Eden space
- Stará generace
- Dorost
- Paměť bez haldy
- Pozorovaná část (pohyblivým ovladačem Spring Boot)
- Metaspace: Referenční hodnota denního využití je 50M–256M
- Mezipaměť kódu
- Komprimovaný prostor třídy
- Nepozorovaná část (nepozorovaná ovladačem Spring Boot): Referenční hodnota denního využití je 150M-250M.
- Zásobník vláken
- GC, vnitřní symbol a další
- Pozorovaná část (pohyblivým ovladačem Spring Boot)
- Přímá paměť: Referenční hodnota denního využití je 10M–200M.
Následující diagram znázorňuje stejné informace. Šedá čísla jsou referenčními hodnotami denního využití paměti.
Celkově byste při konfiguraci maximální velikosti paměti měli zvážit využití každé části paměti a součet všech maximálních velikostí by neměl překročit celkovou dostupnou paměť.
Java OOM
OOM znamená, že aplikace není v paměti. Existují dva různé koncepty: kontejner OOM a OOM JVM. Další informace najdete v tématu Problémy s restartováním aplikace způsobené problémy s nedostatkem paměti.