天天看點

Java虛拟機記憶體調優經驗

轉載自 http://www.cnblogs.com/jackyrong/archive/2010/01/21/1653163.html 尊重别人的勞動成果就是尊重自己

Java記憶體組成 

Java虛拟機記憶體調優經驗

1) 堆

    運作時資料區域,所有類執行個體和數組的記憶體均從此處配置設定。Java 虛拟機啟動時建立。對象的堆記憶體由稱為垃圾回收器 的自動記憶體管理系統回收。

 堆由兩部分組成:

    其中eden+fromspace+tospace也叫年輕代(young),old space叫舊生代.

    其中還有S1,S0(在JDK的自帶工具輸出中會看到),分别指的是Survivor space,存放每次垃圾回收後存活的對象.

    Old Generation , 主要存放應用程式中生命周期長的存活對象

垃圾回收主要是對Young Generation塊和Old Generation塊記憶體進行回收,YG用來放新産生的對象,經過幾次回收還沒回收掉的對象往OG中移動,

對YG進行垃圾回收又叫做MinorGC,對OG垃圾回收叫MajorGC,兩塊記憶體回收互不幹涉

2) 非堆記憶體

   JVM具有一個由所有線程共享的方法區。方法區屬于非堆記憶體。它存儲每個類結構,如運作時常數池、字段和方法資料,以及方法和構造方法的代碼。它是在 Java 虛拟機啟動時建立的。

    除了方法區外,Java 虛拟機實作可能需要用于内部處理或優化的記憶體,這種記憶體也是非堆記憶體。 例如,JIT 編譯器需要記憶體來存儲從 Java 虛拟機代碼轉換而來的本機代碼,進而獲得高性能。 

   Permanent Generation   (圖中的Permanent Space) 存放JVM自己的反射對象,比如類對象和方法對象

3) 回收算法和過程

 JVM采用一種分代回收 (generational collection) 的政策,用較高的頻率對年輕的對象(young generation)進行掃描和回收,這種叫做minor collection,而對老對象(old generation)的檢查回收頻率要低很多,稱為major collection。這樣就不需要每次GC都将記憶體中所有對象都檢查一遍。

      當一個URL被通路時,記憶體申請過程 如下:

A. JVM會試圖為相關Java對象在Eden中初始化一塊記憶體區域

B. 當Eden空間足夠時,記憶體申請結束。否則到下一步

C. JVM試圖釋放在Eden中所有不活躍的對象(這屬于1或更進階的垃圾回收), 釋放後若Eden空間仍然不足以放入新對象,則試圖将部分Eden中活躍對象放入Survivor區

D. Survivor區被用來作為Eden及OLD的中間交換區域,當OLD區空間足夠時,Survivor區的對象會被移到Old區,否則會被保留在Survivor區

E. 當OLD區空間不夠時,JVM會在OLD區進行完全的垃圾收集(0級)

F. 完全垃圾收集後,若Survivor及OLD區仍然無法存放從Eden複制過來的部分對象,導緻JVM無法在Eden區為新對象建立記憶體區域,則出現”out of memory錯誤”

    對象衰老的過程 

    young generation的記憶體,由一塊Eden(伊甸園,有意思)和兩塊Survivor Space(1.4文檔中稱為semi-space)構成。新建立的對象的記憶體都配置設定自eden。兩塊Survivor Space總有會一塊是空閑的,用作copying collection的目标空間。Minor collection的過程就是将eden和在用survivor space中的活對象copy到空閑survivor space中。所謂survivor,也就是大部分對象在伊甸園出生後,根本活不過一次GC。對象在young generation裡經曆了一定次數的minor collection後,年紀大了,就會被移到old generation中,稱為tenuring。(是否僅當survivor space不足的時候才會将老對象tenuring? 目前資料中沒有找到描述)

     剩餘記憶體空間不足會觸發GC,如eden空間不夠了就要進行minor collection,old generation空間不夠要進行major collection,permanent generation空間不足會引發full GC。

4 接下來這部分講解的是TOMCAT或者其他伺服器出現如下錯誤時的分析:

   1、首先是:java.lang.OutOfMemoryError: Java heap space 

解釋: 

Heap size 設定 

JVM堆的設定是指java程式運作過程中JVM可以調配使用的記憶體空間的設定.JVM在啟動的時候會自動設定Heap size的值,其初始空間(即-Xms)是實體記憶體的1/64,最大空間(-Xmx)是實體記憶體的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等選項可進行設定。Heap size 的大小是Young Generation 和Tenured Generaion 之和。 

提示:在JVM中如果98%的時間是用于GC且可用的Heap size 不足2%的時候将抛出此異常資訊。 

提示:Heap Size 最大不要超過可用實體記憶體的80%,一般的要将-Xms和-Xmx選項設定為相同,而-Xmn為1/4的-Xmx值。 

解決方法: 

手動設定Heap size 

修改TOMCAT_HOME/bin/catalina.bat,在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行: 

Java代碼 

set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m   

set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m 

或修改catalina.sh 

在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行: 

JAVA_OPTS="$JAVA_OPTS -server -Xms800m -Xmx800m -XX:MaxNewSize=256m" 

2、其次是:java.lang.OutOfMemoryError: PermGen space 

原因: 

PermGen space的全稱是Permanent Generation space,是指記憶體的永久儲存區域,這塊記憶體主要是被JVM存放Class和Meta資訊的,Class在被Loader時就會被放到PermGen space中,它和存放類執行個體(Instance)的Heap區域不同,GC(Garbage Collection)不會在主程式運作期對PermGen space進行清理,是以如果你的應用中有很CLASS的話,就很可能出現PermGen space錯誤,這種錯誤常見在web伺服器對JSP進行pre compile的時候。如果你的WEB APP下都用了大量的第三方jar, 其大小超過了jvm預設的大小(4M)那麼就會産生此錯誤資訊了。 

解決方法: 

1. 手動設定MaxPermSize大小 

修改TOMCAT_HOME/bin/catalina.bat(Linux下為catalina.sh),在Java代碼 

“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:    

set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m   

“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行: 

set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m 

catalina.sh下為: 

Java代碼 

JAVA_OPTS="$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m"  

JAVA_OPTS="$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m"

JVM的預設設定

堆 (heap)(News Generation 和Old Generaion 之和)的設定

       初始配置設定的記憶體由-Xms指定,預設是實體記憶體的1/64但小于1G。

       最大配置設定的記憶體由-Xmx指定,預設是實體記憶體的1/4但小于1G。

       預設空餘堆記憶體小于40%時,JVM就會增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=指定。 

預設空餘堆記憶體大于70%時,JVM會減少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=指定。

伺服器一般設定-Xms、-Xmx相等以避免在每次GC 後調整堆的大小,是以上面的兩個參數沒啥用。 

       -Xmn 設定young generation的heap大小

      -XX:MinHeapFreeRatio與-XX:MaxHeapFreeRatio設定空閑記憶體占總記憶體的比例範圍,這兩個參數會影響GC的頻率和單次GC的耗時。-XX:NewRatio決定young與old generation的比例。Young generation空間越大,minor collection頻率越低,但是old generation空間小了,又可能導緻major collection頻率增加。-XX:NewSize和-XX:MaxNewSize直接指定了young generation的預設大小和最大大小。

非堆記憶體 的設定

     預設配置設定為64M

     -XX:PermSize設定最小配置設定空間,-XX:MaxPermSize設定最大配置設定空間。一般把這兩個數值設為相同,以減少申請記憶體空間的時間。

再講解和筆記下,JDK下的一些相關看記憶體管理工具的使用:

檢視jvm記憶體狀态:

jstat -gcutil pid 1000 20

異常情況的例子

jstat -gcutil pid 1000 20

 S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT  

  0.00   0.00  99.99  82.51  53.11   2409    1.205 10117 7250.393 7251.598

  0.00   0.00  83.42  82.55  53.10   2409    1.205 10118 7252.650 7253.855

  0.00   0.00  56.06  82.46  53.10   2410    1.205 10120 7254.467 7255.672

  0.00   0.00  32.11  82.55  53.10   2411    1.205 10121 7256.673 7257.877

  0.00   0.00  99.99  82.55  53.10   2412    1.205 10123 7257.026 7258.231

  0.00   0.00  76.00  82.50  53.10   2412    1.205 10124 7259.241 7260.446

這個資料顯示Full GC頻繁發生。

 正常情況的例子

  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT

  0.00   0.00   0.24  55.39  99.60    171    0.667  1339  393.364  394.031

  0.00   0.00   0.24  55.39  99.60    171    0.667  1339  393.364  394.031

  0.00   0.00   0.24  55.39  99.60    171    0.667  1339  393.364  394.031

  0.00   0.00   0.24  55.39  99.60    171    0.667  1339  393.364  394.031

  0.00   0.00   0.24  55.39  99.60    171    0.667  1339  393.364  394.031

  0.00   0.00   0.24  55.39  99.60    171    0.667  1339  393.364  394.031

參數含義:

S0:Heap上的 Survivor space 0 段已使用空間的百分比 

S1:Heap上的 Survivor space 1 段已使用空間的百分比 

E: Heap上的 Eden space 段已使用空間的百分比 

O: Heap上的 Old space 段已使用空間的百分比 

P: Perm space 已使用空間的百分比 

YGC:從程式啟動到采樣時發生Young GC的次數 

YGCT:Young GC所用的時間(機關秒) 

FGC:從程式啟動到采樣時發生Full GC的次數 

FGCT:Full GC所用的時間(機關秒) 

GCT:用于垃圾回收的總時間(機關秒) 

 2         Dump出記憶體

2.1       找出要dump的線程pid

在Linux下,使用ps –aux

2.2       Dump出記憶體使用詳情

可以通過指令:

jmap -dump:file=a.hprof pid

例如:jmap -heap 2343,可以看到

Attaching to process ID 2343, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 11.0-b16

using thread-local object allocation.

Parallel GC with 8 thread(s)

Heap Configuration:

   MinHeapFreeRatio = 40

   MaxHeapFreeRatio = 70

   MaxHeapSize      = 4294967296 (4096.0MB)

   NewSize          = 2686976 (2.5625MB)

   MaxNewSize       = -65536 (-0.0625MB)

   OldSize          = 5439488 (5.1875MB)

   NewRatio         = 2                   (YG,OG 大小比為1:2)

   SurvivorRatio    = 8

   PermSize         = 21757952 (20.75MB)

   MaxPermSize      = 268435456 (256.0MB)

Heap Usage:

PS Young Generation

Eden Space:

   capacity = 1260060672 (1201.6875MB)

   used     = 64868288 (61.86322021484375MB)

   free     = 1195192384 (1139.8242797851562MB)

   5.148028935546367% used

From Space:

   capacity = 85524480 (81.5625MB)

   used     = 59457648 (56.70323181152344MB)

   free     = 26066832 (24.859268188476562MB)

   69.52120375359195% used

To Space:

   capacity = 85852160 (81.875MB)

   used     = 0 (0.0MB)

   free     = 85852160 (81.875MB)

   0.0% used

~~~~~~~~~~~~~~~~~~~~~~~~~~這三塊為上面所說的YG大小和使用情況

PS Old Generation

   capacity = 2291138560 (2185.0MB)

   used     = 1747845928 (1666.8757705688477MB)

   free     = 543292632 (518.1242294311523MB)

   76.28722062099989% used

~~~~~~~~~~~~~~~~~~~~~~~~~~OG大小和使用情況

PS Perm Generation

   capacity = 108265472 (103.25MB)

   used     = 107650712 (102.6637191772461MB)

   free     = 614760 (0.5862808227539062MB)

   99.43217353728436% used

jstat

jstat是vm的狀态監控工具,監控的内容有類加載、運作時編譯及GC。

使用時,需加上檢視程序的程序id,和所選參數。以下詳細介紹各個參數的意義。  

    jstat -class pid:顯示加載class的數量,及所占空間等資訊。  

    jstat -compiler pid:顯示VM實時編譯的數量等資訊。  

    jstat -gc pid:可以顯示gc的資訊,檢視gc的次數,及時間。其中最後五項,分别是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。  

    jstat -gccapacity:可以顯示,VM記憶體中三代(young,old,perm)對象的使用和占用大小,如:PGCMN顯示的是最小perm的記憶體使用量,PGCMX顯示的是perm的記憶體最大使用量,PGC是目前新生成的perm記憶體占用量,PC是但前perm記憶體占用量。其他的可以根據這個類推, OC是old内純的占用量。  

    jstat -gcnew pid:new對象的資訊。  

    jstat -gcnewcapacity pid:new對象的資訊及其占用量。  

    jstat -gcold pid:old對象的資訊。  

    jstat -gcoldcapacity pid:old對象的資訊及其占用量。  

    jstat -gcpermcapacity pid: perm對象的資訊及其占用量。  

    jstat -util pid:統計gc資訊統計。  

    jstat -printcompilation pid:目前VM執行的資訊。  

    除了以上一個參數外,還可以同時加上 兩個數字,如:jstat -printcompilation 3024 250 6是每250毫秒列印一次,一共列印6次,還可以加上-h3每三行顯示一下标題。  

例子:

jstat -gcutil pid 1000 20

 S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   

 47.49   0.00  64.82  46.08  47.69  20822 2058.631    68   22.734 2081.365

  0.00  37.91  38.57  46.13  47.69  20823 2058.691    68   22.734 2081.425  這裡發生了一次YG GC,也就是MinorGC,耗時0.06s

 46.69   0.00  15.19  46.18  47.69  20824 2058.776    68   22.734 2081.510

 46.69   0.00  74.59  46.18  47.69  20824 2058.776    68   22.734 2081.510

  0.00  40.29  19.95  46.24  47.69  20825 2058.848    68   22.734 2081.582

MajorGC平均時間:22.734/68=0.334秒

MinorGC平均時間:2058.691/20823=0.099秒

繼續閱讀