Gestione della memoria Java

Nota

Azure Spring Apps è il nuovo nome del servizio Azure Spring Cloud. Anche se il servizio ha un nuovo nome, il nome precedente verrà visualizzato in alcune posizioni per un po' mentre si lavora per aggiornare gli asset, ad esempio screenshot, video e diagrammi.

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 ha diverse parti e esistono diversi modi per dividere le parti. 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 macchina virtuale Java (JVM) ha una sola area heap, condivisa tra i thread.

Spring Boot Analyzer può osservare il valore della memoria dell'heap. L'attuatore Spring Boot 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 giovani generazioni e vecchia generazione. Questi termini sono descritti nell'elenco seguente, insieme ai termini correlati.

  • Giovani generazioni: tutti i nuovi oggetti vengono allocati e invecchiati in giovane generazione.

    • Spazio Eden: nuovi oggetti vengono allocati nello spazio Eden.
    • Spazio sopravvissuto: gli oggetti verranno spostati da Eden allo spazio sopravvissuto dopo aver sopravvissuto un ciclo di Garbage Collection. Lo spazio sopravvissuto può essere diviso in due parti: s1 e s2.
  • Vecchia generazione: chiamato anche spazio tenurito. Gli oggetti che sono rimasti negli spazi sopravvissuti per molto tempo verranno spostati alla vecchia generazione.

Prima di Java 8, anche un'altra sezione denominata generazione permanente faceva parte dell'heap. A partire da Java 8, la generazione permanente è stata sostituita da metaspace nella memoria non heap.

Memoria non heap

La memoria non heap è suddivisa nelle parti seguenti:

  • Parte della memoria non heap che ha sostituito la generazione permanente (o permGen) a partire da Java 8. L'attuatore Spring Boot osserva questa sezione e lo prende come parte di jvm.memory.used/committed/max. In altre parole, jvm.memory.used/committed/max è la somma della memoria dell'heap e della parte precedente permGen della memoria non heap. La prima generazione permanente è costituita dalle parti seguenti:

    • Metaspace, che archivia le definizioni di classe caricate dai caricatori di classi.
    • Spazio della classe compresso, che è per i puntatori di classe compressi.
    • Cache del codice, che archivia il codice nativo compilato da JIT.
  • Altra memoria, ad esempio lo stack di thread, che non è osservata dall'attuatore Spring Boot.

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

Garbage Collection Java

Esistono tre termini relativi a Java Garbage Collection (GC): "Minor GC", "Major GC" e "Full GC". Questi termini non sono chiaramente definiti nella specifica JVM. In questo caso, si considera che "GC principale" e "Full GC" siano equivalenti.

GC secondario esegue quando lo spazio Eden è pieno. Rimuove tutti gli oggetti morti nella giovane generazione e sposta gli oggetti vivi da spazio Eden a s1 dello spazio sopravvissuto, o da s1 a s2.

Il processo GC completo o GC principale esegue l'operazione di Garbage Collection nell'intero heap. Il processo GC completo può anche raccogliere parti come metaspace e memoria diretta, che possono essere pulite solo da GC completo.

La dimensione massima dell'heap influisce sulla frequenza di GC secondario e GC completo. Il metaspace massimo e la dimensione massima della memoria diretta influisce su GC completo.

Quando si imposta la dimensione massima dell'heap su un valore inferiore, le operazioni di Garbage Collection vengono eseguite più frequentemente, rallentando leggermente l'app, ma limita meglio l'utilizzo della memoria. Quando si impostano le dimensioni massime dell'heap su un valore superiore, le operazioni di Garbage Collection si verificano meno frequentemente, con un rischio maggiore di memoria insufficiente. Per altre informazioni, vedere la sezione Tipi di problemi di memoria insufficiente di Problemi di riavvio dell'app causati da problemi di memoria insufficiente.

Metaspace e memoria diretta possono essere raccolti solo da GC completo. Quando la metaspace o la memoria diretta è piena, si verificherà il processo GC completo.

Configurazioni di memoria Java

Le sezioni seguenti descrivono aspetti importanti della configurazione della memoria Java.

Containerizzazione Java

Le applicazioni in Azure Spring Apps vengono eseguite in ambienti contenitore. Per altre informazioni, vedere Containerize your Java applications .For more information, see Containerize your Java applications.

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 descrive le opzioni di JVM:

  • Configurazione delle dimensioni dell'heap

    • -Xms imposta le dimensioni dell'heap iniziale in base al valore assoluto.
    • -Xmx imposta la dimensione massima dell'heap in base al valore assoluto.
    • -XX:InitialRAMPercentage imposta le dimensioni iniziali dell'heap in base alla percentuale delle dimensioni dell'heap o della memoria dell'app.
    • -XX:MaxRAMPercentage imposta le dimensioni massime dell'heap in base alla percentuale di dimensioni dell'heap/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 metaspace

    • -XX:MaxMetaspaceSize imposta la dimensione massima del metaspace in base al valore assoluto.

Dimensioni massime di memoria predefinite

Le sezioni seguenti descrivono come vengono impostate le dimensioni massime di memoria predefinite.

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 <= memoria dell'app 2 GB, le dimensioni massime predefinite dell'heap < saranno pari al 60% della memoria dell'app.
  • Se 2 GB <= memoria dell'app 3 GB, le dimensioni massime predefinite dell'heap < saranno pari al 70% della memoria dell'app.
  • Se 3 GB <= memoria dell'app, le dimensioni massime predefinite dell'heap saranno pari all'80% della memoria dell'app.

Dimensioni massime massime predefinite della memoria diretta

Quando le dimensioni massime della memoria diretta non vengono impostate usando le opzioni JVM, la JVM imposta automaticamente le dimensioni massime della memoria diretta sul valore restituito da Runtime.getRuntime.maxMemory(). Questo valore è approssimativamente uguale alla dimensione massima della memoria dell'heap. Per altre informazioni, vedere il file di VM.java JDK 8.

Layout utilizzo memoria

Le dimensioni dell'heap sono influenzate dalla velocità effettiva. Fondamentalmente, durante la configurazione, è possibile mantenere le dimensioni massime dell'heap predefinite, che lasciano memoria ragionevole per altre parti.

Le dimensioni del metaspace 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 di memoria per le app da 2 GB. È possibile fare riferimento a questo elenco per configurare le impostazioni delle dimensioni della memoria.

  • Memoria totale (2048M)
  • Memoria heap: Xmx è 1433,6M (70% della memoria totale). Il valore di riferimento dell'utilizzo giornaliero della memoria è 1200M.
    • Giovane generazione
      • Spazio sopravvissuto (S0, S1)
      • Spazio Eden
    • Vecchia generazione
  • Memoria non heap
    • Parte osservata (osservata dall'attuatore Spring Boot)
      • Metaspace: il valore di riferimento di utilizzo giornaliero è 50M-256M
      • Cache del codice
      • Spazio classi compresso
    • Parte non osservata (non osservata dall'attuatore Spring Boot): il valore di riferimento di utilizzo giornaliero è 150M-250M.
      • Stack di thread
      • GC, simbolo interno e altro
  • Memoria diretta: il valore di riferimento di utilizzo giornaliero è 10M-200M.

Il diagramma seguente mostra le stesse informazioni. I numeri in grigio sono i valori di riferimento dell'utilizzo giornaliero della memoria.

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

In generale, quando si configurano dimensioni massime di 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 OOM

OOM indica che l'applicazione non è in memoria. Esistono due concetti diversi: OOM del contenitore e OOM JVM. Per altre informazioni, vedere Problemi di riavvio delle app causati da problemi di memoria insufficiente.

Vedi anche