Dela via


Minneshantering i Java

Kommentar

Azure Spring Apps är det nya namnet på Azure Spring Cloud-tjänsten. Även om tjänsten har ett nytt namn ser du det gamla namnet på vissa platser ett tag medan vi arbetar med att uppdatera tillgångar som skärmbilder, videor och diagram.

Den här artikeln gäller för: ✔️ Basic/Standard ✔️ Enterprise

Den här artikeln beskriver olika begrepp som rör Java-minneshantering som hjälper dig att förstå beteendet för Java-program som finns i Azure Spring Apps.

Java-minnesmodell

Ett Java-programs minne har flera delar och det finns olika sätt att dela upp delarna. I den här artikeln beskrivs Java-minne som indelat i heapminne, icke-heapminne och direkt minne.

Heapminne

Heap-minnet lagrar alla klassinstanser och matriser. Varje virtuell Java-dator (JVM) har bara ett heap-område, som delas mellan trådar.

Spring Boot-ställdon kan observera värdet för heapminnet. Spring Boot-ställdonet tar heap-värdet som en del av jvm.memory.used/committed/max. Mer information finns i avsnittet jvm.memory.used/committed/max i Verktyg för att felsöka minnesproblem.

Heapminnet är indelat i ung generation och gammal generation. Dessa termer beskrivs i följande lista, tillsammans med relaterade termer.

  • Ung generation: alla nya objekt tilldelas och åldras i den unga generationen.

    • Eden utrymme: nya objekt tilldelas i Eden utrymme.
    • Överlevande utrymme: objekt kommer att flyttas från Eden till överlevande utrymme efter att ha överlevt en skräpinsamlingscykel. Överlevnadsutrymme kan delas upp i två delar: s1 och s2.
  • Gammal generation: även kallat besittningsrätt utrymme. Objekt som har varit kvar i efterlevandeutrymmena under lång tid kommer att flyttas till den gamla generationen.

Före Java 8 var ett annat avsnitt som kallas permanent generation också en del av heapen. Från och med Java 8 ersattes den permanenta generationen av metarymden i icke-heapminne.

Minne som inte är heap

Icke-heapminne är indelat i följande delar:

  • Den del av icke-heapminnet som ersatte den permanenta generationen (eller permGen) som börjar med Java 8. Spring Boot-aktuatorn observerar det här avsnittet och tar det som en del av jvm.memory.used/committed/max. Med andra ord är jvm.memory.used/committed/max summan av heapminnet och den tidigare permGen-delen av icke-heapminnet. Den tidigare permanenta generationen består av följande delar:

    • Metaområde, som lagrar klassdefinitionerna som läses in av klassinläsare.
    • Komprimerat klassutrymme, vilket är för komprimerade klasspekare.
    • Kodcache, som lagrar inbyggd kod som kompilerats av JIT.
  • Annat minne, till exempel trådstacken, som inte observeras av Spring Boot-ställdonet.

Direkt minne

Direktminne är inbyggt minne som allokeras av java.nio.DirectByteBuffer, som används i bibliotek från tredje part som nio och gzip.

Spring Boot-ställdonet observerar inte värdet för direkt minne.

Följande diagram sammanfattar Java-minnesmodellen som beskrivs i föregående avsnitt.

Diagram som visar Java-minnesmodellen.

Java-skräpinsamling

Det finns tre termer för Java Garbage Collection (GC): "Minor GC", "Major GC" och "Full GC". Dessa termer definieras inte tydligt i JVM-specifikationen. Här anser vi att "Major GC" och "Full GC" är likvärdiga.

Minor GC uppträder när Eden-utrymmet är fullt. Det tar bort alla döda föremål i ung generation och flyttar levande föremål till från Eden-rymden till s1 av överlevande utrymme, eller från s1 till s2.

Fullständig GC eller större GC gör skräpinsamling i hela heapen. Fullständig GC kan också samla in delar som metaområde och direkt minne, som endast kan rensas av fullständig GC.

Den maximala heapstorleken påverkar frekvensen för mindre GC och fullständig GC. Den maximala metarymden och den maximala direkta minnesstorleken påverkar fullständig GC.

När du anger den maximala heapstorleken till ett lägre värde sker skräpsamlingar oftare, vilket gör appen lite långsammare, men begränsar minnesanvändningen bättre. När du anger den maximala heapstorleken till ett högre värde sker skräpsamlingar mindre ofta, vilket kan skapa mer out-of-memory-risk (OOM). Mer information finns i avsnittet Typer av problem med minnesbrist i problem med appomstart som orsakas av problem med minnesbrist.

Metarymd och direkt minne kan endast samlas in av fullständig GC. När metaområdet eller direktminnet är fullt, kommer fullständig GC att ske.

Java-minneskonfigurationer

I följande avsnitt beskrivs viktiga aspekter av Java-minneskonfigurationen.

Java-containerisering

Program i Azure Spring Apps körs i containermiljöer. Mer information finns i Containerize your Java applications (Containerize your Java applications).

Viktiga JVM-alternativ

Du kan konfigurera den maximala storleken för varje del av minnet med hjälp av JVM-alternativ. Du kan ange JVM-alternativ med hjälp av Azure CLI-kommandon eller via Azure-portalen. Mer information finns i avsnittet Ändra konfigurationer för att åtgärda problem i Verktyg för att felsöka minnesproblem.

I följande lista beskrivs JVM-alternativen:

  • Konfiguration av heapstorlek

    • -Xms anger den inledande heapstorleken efter absolut värde.
    • -Xmx anger den maximala heapstorleken efter absolut värde.
    • -XX:InitialRAMPercentage anger den ursprungliga heapstorleken med procentandelen heapstorlek/appminnesstorlek.
    • -XX:MaxRAMPercentage anger den maximala heapstorleken med procentandelen heapstorlek/appminnesstorlek.
  • Konfiguration av direkt minnesstorlek

    • -XX:MaxDirectMemorySize anger den maximala direkta minnesstorleken efter absolut värde. Mer information finns i MaxDirectMemorySize i Oracle-dokumentationen.
  • Konfiguration av metaområdesstorlek

    • -XX:MaxMetaspaceSize anger den maximala metarymdsstorleken efter absolut värde.

Maximal minnesstorlek som standard

I följande avsnitt beskrivs hur standardstorlekar för maximalt minne anges.

Standardstorlek för maximal heap

Azure Spring Apps anger den maximala standardminnesstorleken för heap till cirka 50–80 % av appminnet för Java-appar. Mer specifikt använder Azure Spring Apps följande inställningar:

  • Om appens minne < är 1 GB är den maximala standardstorleken för heap 50 % av appminnet.
  • Om 1 GB <= appminnet < 2 GB är den maximala standardstorleken för heap 60 % av appminnet.
  • Om 2 GB <= appminnet < 3 GB är den maximala standardstorleken för heap 70 % av appminnet.
  • Om 3 GB <= appminnet är den maximala standardstorleken för heap 80 % av appminnet.

Standardstorlek för maximalt direkt minne

När den maximala direktminnesstorleken inte har angetts med JVM-alternativ anger JVM automatiskt den maximala direkta minnesstorleken till det värde som returneras av Runtime.getRuntime.maxMemory(). Det här värdet är ungefär lika med den maximala minnesstorleken för heap. Mer information finns i JDK 8-VM.java-filen.

Layout för minnesanvändning

Heapstorleken påverkas av ditt dataflöde. När du konfigurerar kan du behålla standardstorleken för maximal heap, vilket lämnar rimligt minne för andra delar.

Metarymdens storlek beror på kodens komplexitet, till exempel antalet klasser.

Den direkta minnesstorleken beror på ditt dataflöde och din användning av bibliotek från tredje part som nio och gzip.

I följande lista beskrivs ett typiskt exempel på minneslayout för 2 GB-appar. Du kan referera till den här listan för att konfigurera inställningarna för minnesstorlek.

  • Totalt minne (2048 M)
  • Heapminne: Xmx är 1433,6 M (70 % av det totala minnet). Referensvärdet för den dagliga minnesanvändningen är 1200M.
    • Ung generation
      • Överlevande utrymme (S0, S1)
      • Eden utrymme
    • Gammal generation
  • Minne som inte är heap
    • Observerad del (observerad av Spring Boot-aktuator)
      • Metaområde: referensvärdet för daglig användning är 50M–256 M
      • Kodcache
      • Komprimerat klassutrymme
    • Ej observerad del (observeras inte av Spring Boot-aktuator): det dagliga användningsreferensvärdet är 150M-250M.
      • Trådstack
      • GC, intern symbol och annat
  • Direkt minne: referensvärdet för daglig användning är 10M–200M.

Följande diagram visar samma information. Tal i grått är referensvärdena för daglig minnesanvändning.

Diagram över typisk minneslayout för 2 GB-appar.

När du konfigurerar maximala minnesstorlekar bör du överväga användningen av varje del i minnet, och summan av alla maximala storlekar bör inte överstiga det totala tillgängliga minnet.

Java OOM

OOM innebär att programmet har slut på minne. Det finns två olika begrepp: container-OOM och JVM OOM. Mer information finns i Problem med omstart av appar som orsakas av minnesbrist.

Se även