Condividi tramite


Gestione della memoria Java

Nota

I piani Basic, Standard ed Enterprise sono entrati in un periodo di ritiro il 17 marzo 2025. Per altre informazioni, vedere l'annuncio di ritiro di Azure Spring Apps.

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) ha una sola area heap, condivisa tra i thread.

Spring Boot Actuator può osservare il valore della memoria 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: tutti i nuovi oggetti vengono allocati e invecchiati nella giovane generazione.

    • 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, la generazione permanente è stata sostituita dal metaspazio nella memoria al di fuori dell'heap.

Memoria non-heap

La memoria non heap è divisa nelle parti seguenti:

  • La parte della memoria non heap che ha sostituito la 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 generazione permanente precedente è composta dalle seguenti parti:

    • 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.

Diagramma che mostra il modello di memoria Java.

Raccolta rifiuti di Java

Esistono tre termini relativi a Garbage Collection Java (GC): "GC minore", "GC maggiore" e "GC completo". Questi termini non sono chiaramente definiti nella specifica JVM. In questo articolo "GC principale" e "GC completo" vengono considerati equivalenti.

Il GC minore viene eseguito quando l'Eden space raggiunge la capacità massima. Rimuove tutti gli oggetti morti nella generazione giovane e sposta gli oggetti attivi dallo spazio Eden allo spazio s1 del spazio sopravvissuto oppure dal s1 al s2.

GC completo o GC maggiore esegue Garbage Collection nell'intero heap. GC completo può anche raccogliere parti come il metaspazio e la memoria diretta, che possono essere pulite solo da GC completo.

La dimensione massima dell'heap influisce sulla frequenza di GC minore e GC completo. Le dimensioni massime del metaspace e della memoria diretta influenzano il full GC.

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 sono pieni, si verifica il full GC.

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.

Dimensione massima predefinita 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 la memoria dell'app è compresa tra 1 GB < e < 2 GB, la dimensione massima predefinita dell'heap sarà 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 la memoria dell'app è pari a 3 GB <, 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 capacità di elaborazione. 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: Il parametro Xmx è 1433,6 M (70% della memoria di sistema). Il valore di riferimento dell'utilizzo giornaliero della memoria è 1200 M.
    • Giovane generazione
      • Spazio di Sopravvivenza (S0, S1)
      • Eden Space
    • Vecchia Generazione
  • Memoria non heap
    • Parte osservata (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
  • 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.

Diagramma del layout della memoria tipico per le app da 2 GB.

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.

Java memoria insufficiente (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.

Vedi anche