Gestione della memoria Java
Nota
I piani Basic, Standard ed Enterprise saranno deprecati a partire dalla metà di marzo 2025, con un periodo di ritiro di 3 anni. È consigliabile eseguire la transizione ad App Azure Container. Per altre informazioni, vedere l'annuncio di ritiro di Azure Spring Apps.
Il piano Standard a consumo e dedicato sarà deprecato a partire dal 30 settembre 2024, con un arresto completo dopo sei mesi. È consigliabile eseguire la transizione ad App Azure Container. Per altre informazioni, vedere Eseguire la migrazione del consumo di Azure Spring Apps Standard e del piano dedicato alle app Azure Container.
Questo articolo si applica a:✅ Basic/Standard ❎ Enterprise
Questo articolo descrive vari concetti relativi alla gestione della memoria Java per comprendere il comportamento delle applicazioni Java ospitate in Azure Spring Apps.
Modello di memoria Java
La memoria di un'applicazione Java comprende diverse parti ed esistono diversi modi per dividerle. Questo articolo illustra la memoria Java divisa in memoria heap, memoria non heap e memoria diretta.
Memoria heap
La memoria heap archivia tutte le istanze di classe e le matrici. Ogni Java Virtual Machine (JVM) include una sola area heap, condivisa tra i thread.
Spring Boot Actuator può osservare il valore della memoria dell'heap. Spring Boot Actuator accetta il valore dell'heap come parte di jvm.memory.used/committed/max
. Per altre informazioni, vedere la sezione jvm.memory.used/committed/max in Strumenti per risolvere i problemi di memoria.
La memoria heap è divisa in Young Generation e Old Generation. Questi termini sono descritti nell'elenco seguente, insieme ai termini correlati.
Young Generation: in questa area vengono allocati tutti i nuovi oggetti fino all'obsolescenza.
- Eden Space: in questo spazio vengono allocati i nuovi oggetti.
- Survivor Space: in questo spazio vengono spostati da Eden Space gli oggetti sopravvissuti a un ciclo di Garbage Collection. Survivor Space può essere diviso in due parti: s1 e s2.
Old Generation: anche detto Tenured Space. Gli oggetti rimasti in Survivor Space per un lungo periodo ti tempo verranno spostati in Old Generation.
Prima di Java 8, la memoria heap includeva anche un'altra sezione, denominata Permanent Generation. A partire da Java 8, Permanent Generation è stata sostituita dal metaspazio nella memoria non heap.
Memoria non heap
La memoria non heap è divisa nelle parti seguenti:
La parte della memoria non heap che ha sostituito Permanent Generation (o permGen) a partire da Java 8. Spring Boot Actuator osserva questa sezione e la accetta come parte di
jvm.memory.used/committed/max
. In altre parole,jvm.memory.used/committed/max
è la somma della memoria heap e della parte permGen precedente della memoria non heap. La sezione Permanent Generation precedente è composta dalle parti seguenti:- Metaspazio, che archivia le definizioni di classe caricate dai caricatori di classe.
- Spazio di classi compresse, destinato ai puntatori di classi compresse.
- Cache di codice, che archivia il codice nativo compilato da JIT.
Altri tipi di memoria, ad esempio lo stack di thread, che non vengono osservati da Spring Boot Actuator.
Memoria diretta
La memoria diretta è la memoria nativa allocata da java.nio.DirectByteBuffer
, che viene usata in librerie di terze parti come nio e gzip.
Spring Boot Actuator non osserva il valore della memoria diretta.
Il diagramma seguente riepiloga il modello di memoria Java descritto nella sezione precedente.
Garbage Collection Java
Esistono tre termini relativi a Garbage Collection Java (GC): "GC secondario", "GC principale" e "GC completo". Questi termini non sono chiaramente definiti nella specifica JVM. In questo articolo "GC principale" e "GC completo" vengono considerati equivalenti.
GC secondario viene eseguito quando Eden Space è pieno. Rimuove tutti gli obsoleti in Young Generation e sposta gli oggetti attivi da Eden Space a s1 di Survivor Space oppure da s1 a s2.
GC completo o GC principale esegue Garbage Collecton nell'intero heap. GC completo può anche raccogliere parti come il metaspazio e la memoria diretta, che possono essere pulite solo da GC completo.
Le dimensioni massime dell'heap influiscono sulla frequenza di esecuzione di GC secondario e GC completo. Le dimensioni massime del metaspazio e della memoria diretta influiscono su GC completo.
Quando le dimensioni massime dell'heap vengono impostate su un valore minore, le operazioni di Garbage Collection vengono eseguite più frequentemente, rallentando leggermente l'app, ma limitando meglio l'utilizzo della memoria. Quando le dimensioni massime dell'heap vengono impostate su un valore maggiore, le operazioni di Garbage Collection vengono eseguite meno frequentemente, aumentando il rischio di memoria insufficiente. Per altre informazioni, vedere la sezione Tipi di problemi di memoria insufficiente di Problemi di riavvio delle app causati da problemi di memoria insufficiente.
Le parti metaspazio e memoria diretta possono essere raccolte solo da Full GC. Quando il metaspazio o la memoria diretta è piena, viene eseguito GC completo.
Configurazioni della memoria Java
Le sezioni seguenti descrivono aspetti importanti della configurazione della memoria Java.
Containerizzazione di Java
Le applicazioni in Azure Spring Apps vengono eseguite in ambienti contenitore. Per altre informazioni, vedere Inserire le applicazioni Java in contenitori.
Opzioni importanti di JVM
È possibile configurare le dimensioni massime di ogni parte della memoria usando le opzioni JVM. È possibile impostare le opzioni JVM usando i comandi dell'interfaccia della riga di comando di Azure o tramite il portale di Azure. Per altre informazioni, vedere la sezione Modificare le configurazioni per risolvere i problemi di Strumenti per risolvere i problemi di memoria.
L'elenco seguente offre una descrizione delle opzioni JVM:
Configurazione delle dimensioni dell'heap
-
-Xms
imposta le dimensioni iniziali dell'heap in base al valore assoluto. -
-Xmx
imposta le dimensioni massime dell'heap in base al valore assoluto. -
-XX:InitialRAMPercentage
imposta le dimensioni iniziali dell'heap in base alla percentuale di dimensioni dell'heap/dimensioni della memoria dell'app. -
-XX:MaxRAMPercentage
imposta le dimensioni massime dell'heap in base alla percentuale di dimensioni dell'heap/dimensioni della memoria dell'app.
-
Configurazione delle dimensioni della memoria diretta
-
-XX:MaxDirectMemorySize
imposta le dimensioni massime della memoria diretta in base al valore assoluto. Per altre informazioni, vedere MaxDirectMemorySize nella documentazione di Oracle.
-
Configurazione delle dimensioni del metaspazio
-
-XX:MaxMetaspaceSize
imposta le dimensioni massime del metaspazio in base al valore assoluto.
-
Dimensioni massime predefinite della memoria
Le sezioni seguenti descrivono come vengono impostate le dimensioni massime predefinite della memoria.
Dimensioni massime predefinite dell'heap
Azure Spring Apps imposta le dimensioni massime predefinite della memoria heap su circa il 50%-80% della memoria dell'app per le app Java. In particolare, Azure Spring Apps usa le impostazioni seguenti:
- Se la memoria dell'app < 1 GB, le dimensioni massime predefinite dell'heap saranno pari al 50% della memoria dell'app.
- Se 1 GB <= la memoria dell'app < 2 GB, le dimensioni massime predefinite dell'heap saranno pari al 60% della memoria dell'app.
- Se 2 GB <= la memoria dell'app < 3 GB, le dimensioni massime predefinite dell'heap saranno pari al 70% della memoria dell'app.
- Se 3 GB <= la memoria dell'app, le dimensioni massime predefinite dell'heap saranno pari all'80% della memoria dell'app.
Dimensioni massime predefinite della memoria diretta
Quando le dimensioni massime della memoria diretta non vengono impostate tramite le opzioni JVM, JVM le imposta automaticamente sul valore restituito da Runtime.getRuntime.maxMemory(). Questo valore è approssimativamente uguale alle dimensioni massime della memoria heap. Per altre informazioni, vedere il file VM.java JDK 8.
Layout dell'utilizzo della memoria
Le dimensioni dell'heap sono influenzate dalla velocità effettiva. Essenzialmente, durante la configurazione è possibile mantenere le dimensioni massime predefinite dell'heap, il che lascia una quantità di memoria ragionevole per altre parti.
Le dimensioni del metaspazio dipendono dalla complessità del codice, ad esempio il numero di classi.
Le dimensioni della memoria diretta dipendono dalla velocità effettiva e dall'uso di librerie di terze parti, ad esempio nio e gzip.
L'elenco seguente descrive un tipico esempio di layout della memoria per le app da 2 GB. È possibile fare riferimento a questo elenco per configurare le impostazioni delle dimensioni della memoria.
- Memoria totale (2048 M)
- Memoria heap: Xmx è 1433,6 M (70% della memoria totale). Il valore di riferimento dell'utilizzo giornaliero della memoria è 1200 M.
- Young Generation
- Survivor Space (S0, S1)
- Eden Space
- Old Generation
- Young Generation
- Memoria non heap
- Parte osservata (da Spring Boot Actuator)
- Metaspazio: il valore di riferimento di utilizzo giornaliero è 50 M-256 M
- Cache del codice
- Spazio di classi compresse
- Parte non osservata (da Spring Boot Actuator): il valore di riferimento di utilizzo giornaliero è 150 M-250 M.
- Stack di thread
- GC, simbolo interno e altro
- Parte osservata (da Spring Boot Actuator)
- Memoria diretta: il valore di riferimento di utilizzo giornaliero è 10 M-200 M.
Il diagramma seguente mostra le stesse informazioni. I numeri in grigio sono i valori di riferimento dell'utilizzo giornaliero della memoria.
In generale, quando si configurano dimensioni massime della memoria, è consigliabile considerare l'utilizzo di ogni parte in memoria e la somma di tutte le dimensioni massime non deve superare la memoria totale disponibile.
Memoria insufficiente di Java (OOM)
OOM indica una condizione di memoria insufficiente per l'applicazione. Esistono due concetti diversi: OOM del contenitore e OOM della JVM. Per altre informazioni, vedere Problemi di riavvio delle app causati da problemi di memoria insufficiente.