常用的JVM配置引數
常用JVM配置引數
大綱:
n Trace(軌跡/痕跡)跟蹤引數
n 堆的分配引數
n 棧的分配引數
Trace跟蹤引數
-verbose:gc
java -verbose:gc 中引數-verbose:gc 表示輸出虛擬機器中GC的詳細情況.
使用後輸出如下:
[Full GC 168K->97K(1984K), 0.0253873 secs]
解讀如下:
箭頭前後的資料168K和97K分別表示垃圾收集GC前後所有存活物件使用的記憶體容量,說明有168K-97K=71K的物件容量被回收,括號內的資料1984K為堆記憶體的總容量,收集所需要的時間是0.0253873
-XX:+printGC
可以列印GC的簡要資訊
– [GC 4790K->374K(15872K), 0.0001606 secs]
– 4790K:GC前堆被使用的容量
– 374K:GC後堆被使用的容量
– 15872K:堆的總容量
– 0.0001606 secs:本次GC垃圾收集花費的時間
– [GC 4790K->374K(15872K), 0.0001474 secs]
– [GC 4790K->374K(15872K), 0.0001563 secs]
– [GC 4790K->374K(15872K), 0.0001682 secs]
引數配置和理解
1:引數分類和說明
jvm引數分固定引數和非固定引數
1):固定引數
如:-Xmx,-Xms,-Xmn,-Xss.
2):非固定引數
如:
-XX:+<option> 啟用選項
-XX:-<option> 不啟用選項
-XX:<option>=<number> 給選項設定一個數字型別值,可跟單位,例如 128k, 2g
-XX:<option>=<string> 給選項設定一個字串值,例如-XX:HeapDumpPath=./dump.log
-XX:+PrintGCDetails
n -XX:+PrintGCDetails
– 列印GC詳細資訊
– 只要設定-XX:+PrintGCDetails 就會自動帶上-verbose:gc和-XX:+PrintGC
– 在程式結束後,會把整個程式的堆的基本狀況打印出來。
-XX:+PrintGCTimeStamps
n -XX:+PrintGCTimeStamps
– 列印CG發生的時間戳
n 例GC發生的時間戳
– [GC[DefNew: 4416K->0K(4928K), 0.0001897 secs] 4790K->374K(15872K), 0.0002232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
– DefNew:說明這是一個新生代的GC資訊
– 4416K:在GC之前,新生代被使用的記憶體大小
– 0K:GC之後,新生代被使用的記憶體大小
– 4928K:新生代的總記憶體大小
– 0.0001897 secs:新生代GC垃圾收集花費的時間
– 4790K:GC之前堆中總共被使用的記憶體大小
– 374K:GC之後堆中總共被使用的記憶體大小
– 15872K:堆的記憶體總大小
– 0.0002232 secs:整個堆GC垃圾收集所花費的時間
– Times:
– user=0.00:使用者耗時
– sys=0.00:系統耗時
– real=0.00:實際耗時
s
n -XX:+PrintGCDetails在程式結束後的輸出
– Heap[z1]
– def new generation[z2] total[z3] 13824K[z4], used [z5]11223K [0x27e80000[z6](低邊界), 0x28d80000[z7](當前邊界), 0x28d80000[z8](最高邊界)[z9])
– eden space[z10] 12288K[z11], 91% used [0x27e80000, 0x28975f20, 0x28a80000)
– from space[z12] 1536K, 0% used [0x28a80000, 0x28a80000, 0x28c00000)
– to space[z13] 1536K, 0% used [0x28c00000, 0x28c00000, 0x28d80000)
– tenured generation[z14] total 5120K, used 0K [0x28d80000, 0x29280000, 0x34680000)
– the space 5120K, 0% used [0x28d80000, 0x28d80000, 0x28d80200, 0x29280000)
– compacting perm gen[z15] total 12288K, used 142K [0x34680000, 0x35280000, 0x38680000)
– the space 12288K, 1% used [0x34680000, 0x346a3a90, 0x346a3c00, 0x35280000)
– ro space[z16] 10240K, 44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000)
– rw space[z17] 12288K, 52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000)
-Xloggc:log/gc.log
n -Xloggc:log/gc.log(意為:將GC日誌資訊輸出到系統當前位置的log目錄下的gc.log檔案)
– 指定GC log日誌的輸出的位置,以檔案輸出(一般情況下,GC的日誌輸出都是在控制檯的)
– 幫助開發人員分析問題
-XX:+PrintHeapAtGC
n -XX:+PrintHeapAtGC
– 每次一次GC的前後,都列印堆資訊
{Heap before GC invocations=0[z18] (full 0)://GC前,堆記憶體的使用情況 def new generation total 3072K, used 2752K [0x33c80000, 0x33fd0000, 0x33fd0000) eden space 2752K, 100% used [0x33c80000, 0x33f30000, 0x33f30000) from space 320K, 0% used [0x33f30000, 0x33f30000, 0x33f80000) to space 320K, 0% used [0x33f80000, 0x33f80000, 0x33fd0000) tenured generation total 6848K, used 0K [0x33fd0000, 0x34680000, 0x34680000) the space 6848K, 0% used [0x33fd0000, 0x33fd0000, 0x33fd0200, 0x34680000) compacting perm gen total 12288K, used 143K [0x34680000, 0x35280000, 0x38680000) the space 12288K, 1% used [0x34680000, 0x346a3c58, 0x346a3e00, 0x35280000) ro space 10240K, 44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000) rw space 12288K, 52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000) [GC[DefNew: 2752K->320K(3072K), 0.0014296 secs] 2752K->377K(9920K), 0.0014604 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [z19] Heap after GC invocations=1[z20] (full 0)://GC之後,對記憶體的使用情況 def new generation total 3072K, used 320K [0x33c80000, 0x33fd0000, 0x33fd0000) eden space 2752K, 0% used [0x33c80000, 0x33c80000, 0x33f30000) from space 320K, 100% used [0x33f80000, 0x33fd0000, 0x33fd0000) to space 320K, 0% used [0x33f30000, 0x33f30000, 0x33f80000) tenured generation total 6848K, used 57K [0x33fd0000, 0x34680000, 0x34680000) the space 6848K, 0% used [0x33fd0000, 0x33fde458, 0x33fde600, 0x34680000) compacting perm gen total 12288K, used 143K [0x34680000, 0x35280000, 0x38680000) the space 12288K, 1% used [0x34680000, 0x346a3c58, 0x346a3e00, 0x35280000) ro space 10240K, 44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000) rw space 12288K, 52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000) } |
-XX:+TraceClassLoading
n -XX:+TraceClassLoading
– 監控類的載入,檢視哪些類被載入到了虛擬機器
• [Loaded java.lang.Object from shared objects file]
• [Loaded java.io.Serializable from shared objects file]
• [Loaded java.lang.Comparable from shared objects file]
• [Loaded java.lang.CharSequence from shared objects file]
• [Loaded java.lang.String from shared objects file]
• [Loaded java.lang.reflect.GenericDeclaration from shared objects file]
• [Loaded java.lang.reflect.Type from shared objects file]
-XX:+PrintClassHistogram
n -XX:+PrintClassHistogram
– 按下Ctrl+Break[z21]後,列印類的資訊:
num #instances #bytes class name
----------------------------------------------
1: 890617 470266000 [B
2: 890643 21375432 java.util.HashMap$Node
3: 890608 14249728 java.lang.Long
4: 13 8389712 [Ljava.util.HashMap$Node;
5: 2062 371680 [C
6: 463 41904 java.lang.Class
– 分別顯示:序號、例項數量、總大小、型別
堆的分配引數
-Xmx –Xms
n -Xmx –Xms
– 指定最大堆和最小堆
– -Xmx:最大堆,堆最大可以分配擴充套件到多大的空間。
– -Xms:最小堆,堆最小佔用多少空間,系統啟動時給堆初始分配多少空間。
n -Xmx20m -Xms5m 執行程式碼:
– System.out.print("Xmx=");
– System.out.println(Runtime.getRuntime().maxMemory()/1024.0/1024+"M");//列印最大可擴充套件記憶體
– System.out.print("free mem=");
– System.out.println(Runtime.getRuntime().freeMemory()/1024.0/1024+"M");//列印可使用的空閒記憶體
– System.out.print("total mem=");
– System.out.println(Runtime.getRuntime().totalMemory()/1024.0/1024+"M");//列印已分配的總記憶體
列印輸出:Xmx=19.375M
free mem=4.342750549316406M
total mem=4.875M
n -Xmx20m -Xms5m 執行程式碼
– byte[] b=new byte[1*1024*1024];
– System.out.println("分配了1M空間給陣列");
– System.out.print("Xmx=");
– System.out.println(Runtime.getRuntime().maxMemory()/1024.0/1024+"M");
– System.out.print("free mem=");
– System.out.println(Runtime.getRuntime().freeMemory()/1024.0/1024+"M");
– System.out.print("total mem=");
– System.out.println(Runtime.getRuntime().totalMemory()/1024.0/1024+"M");
列印輸出:分配了1M空間給陣列
Xmx=19.375M
free mem=3.4791183471679688M
total mem=4.875M
Java會盡可能維持在最小堆
n -Xmx20m -Xms5m 執行程式碼
n b=new byte[4*1024*1024];
n System.out.println("分配了4M空間給陣列");
n System.out.print("Xmx=");
n System.out.println(Runtime.getRuntime().maxMemory()/1024.0/1024+"M");
n System.out.print("free mem=");
n System.out.println(Runtime.getRuntime().freeMemory()/1024.0/1024+"M");
n System.out.print("total mem=");
n System.out.println(Runtime.getRuntime().totalMemory()/1024.0/1024+"M");
列印輸出:分配了4M空間給陣列
Xmx=19.375M
free mem=3.5899810791015625M
total mem=9.00390625M(分配的總記憶體變多了)
n -Xmx20m -Xms5m 執行程式碼
n System.gc();
n System.out.println("回收記憶體");
n System.out.print("Xmx=");
n System.out.println(Runtime.getRuntime().maxMemory()/1024.0/1024+"M");
n System.out.print("free mem=");
n System.out.println(Runtime.getRuntime().freeMemory()/1024.0/1024+"M");
n System.out.print("total mem=");
n System.out.println(Runtime.getRuntime().totalMemory()/1024.0/1024+"M");
列印輸出:回收記憶體
Xmx=19.375M
free mem=6.354591369628906M(空閒記憶體增多了)
total mem=10.75390625M
-Xmx 和 –Xms 應該保持一個什麼關係,可以讓系統的效能儘可能的好呢?
-Xmn
n -Xmn
– 設定新生代大小
-XX:NewRatio
n -XX:NewRatio
– 新生代(eden+2*s)和老年代(不包含永久區)的比值
– 如果設定為4(-XX:NewRatio=4) ,表示 新生代:老年代=1:4,即年輕代佔堆的1/5
-XX:SurvivorRatio
n -XX:SurvivorRatio
– 設定兩個Survivor(倖存)區和eden(伊甸區)的比
– 如果設定為8(-XX:SurvivorRatio=8),表示 兩個Survivor :eden=2:8,即一個Survivor佔年輕代的1/10
示例:
-Xmx20m -Xms20m -Xmn1m -XX:+PrintGCDetails
程式碼:
public static void main(String[] args) { byte[] b=null; for(int i=0;i<10;i++) b=new byte[1*1024*1024]; } |
執行引數:
-Xmx20m -Xms20m -Xmn1m -XX:+PrintGCDetails
日誌列印:
結果分析
- 沒有觸發GC
- 全部分配在老年代
-Xmx20m -Xms20m -Xmn15m -XX:+PrintGCDetails
程式碼:
public static void main(String[] args) { byte[] b=null; for(int i=0;i<10;i++) b=new byte[1*1024*1024]; } |
執行引數:
-Xmx20m -Xms20m -Xmn15m -XX:+PrintGCDetails
日誌列印:
實際佔用空間大約10M 因為有系統級別的物件 如ClassLoader Thread等
結果分析:
- 沒有觸發GC
- 全部分配在eden
- 老年代沒有使用
-Xmx20m -Xms20m –Xmn7m -XX:+PrintGCDetails
程式碼:
public static void main(String[] args) { byte[] b=null; for(int i=0;i<10;i++) b=new byte[1*1024*1024]; } |
執行引數:
-Xmx20m -Xms20m -Xmn7m -XX:+PrintGCDetails
日誌列印:
一共回收7M 剩餘3M
S0 s1 太小無法週轉
結果分析:
1.進行了2次新生代GC
2.s0 s1 太小需要老年代擔保
-Xmx20m -Xms20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails
程式碼:
public static void main(String[] args) { byte[] b=null; for(int i=0;i<10;i++) b=new byte[1*1024*1024]; } |
執行引數:
-Xmx20m -Xms20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails
日誌列印:
回收7M 剩餘3M
結果分析:
1.進行了3次新生代GC
2.s0(from) s1(to) 增大
-Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:+PrintGCDetails
程式碼:
public static void main(String[] args) { byte[] b=null; for(int i=0;i<10;i++) b=new byte[1*1024*1024]; } |
執行引數:
-Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:+PrintGCDetails
日誌列印:
結果分析:
比例分配,新生代 老年代對半開
物件全部留在新生代
-Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=3 -XX:+PrintGCDetails
程式碼:
public static void main(String[] args) { byte[] b=null; for(int i=0;i<10;i++) b=new byte[1*1024*1024]; } |
執行引數:
-Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=3 -XX:+PrintGCDetails
日誌列印:
結果分析:
減少了s0(from) s1(to) GC數量變少,老年代未使用 空間使用率更高
-XX:+HeapDumpOnOutOfMemoryError
n -XX:+HeapDumpOnOutOfMemoryError
– 發生OOM異常時匯出堆到檔案
-XX:+HeapDumpPath
n -XX:+HeapDumpPath
– 發生OOM異常時,匯出的堆放到檔案的檔案路徑
示例:
-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
執行引數:
-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
程式碼及執行結果:
Vector v=new Vector(); for(int i=0;i<25;i++) v.add(new byte[1*1024*1024]); |
檢視匯出的堆檔案:
-XX:OnOutOfMemoryError
n -XX:OnOutOfMemoryError
– 在發生OOM異常時,執行一個指令碼
– 引數示例:"-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p[z22]”
– printstack.bat 的內容:D:/tools/jdk1.7_40/bin/jstack -F %1 > D:/a.txt
– 當程式OOM時,在D:/a.txt中將會生成執行緒的dump
– 也可以在OOM時,傳送郵件,甚至是重啟程式,主要看指令碼怎麼寫。
堆的分配引數 – 總結
n 根據實際事情調整新生代和倖存代的大小
n 官方推薦新生代佔堆的3/8
n 倖存代佔新生代的1/10
n 在OOM時,記得Dump出堆,確保可以排查現場問題
永久區分配引數
-XX:PermSize -XX:MaxPermSize
n -XX:PermSize -XX:MaxPermSize
– 設定永久區的初始空間和最大空間
– 他們表示,一個系統可以容納多少個型別(即可以載入多少個.class檔案)
示例:
n 使用CGLIB等庫的時候,可能會產生大量的類,這些類,有可能撐爆永久區導致OOM異常
程式碼:
for(int i=0;i<100000;i++){ CglibBean bean = new CglibBean("geym.jvm.ch3.perm.bean"+i,new HashMap());//不斷產生新的類 } |
檢視日誌:
分析導致OOM異常的原因
n 開啟堆的Dump(匯出檔案)
– 堆空間實際佔用非常少
– 但是永久區溢位 一樣丟擲OOM
如果堆空間沒有用完也丟擲了OOM,有可能是永久區導致的
棧大小分配
-Xss
n -Xss
– 通常只有幾百K
– 決定了函式呼叫的深度
– 每個執行緒都有獨立的棧空間
– 區域性變數、方法引數 分配在棧上
示例:
程式碼:
public class TestStackDeep { private static int count=0; public static void recursion(long a,long b,long c){ long e=1,f=2,g=3,h=4,i=5,k=6,q=7,x=8,y=9,z=10; count++; recursion(a,b,c);//遞迴呼叫 } public static void main(String args[]){ try{ recursion(0L,0L,0L); }catch(Throwable e){ System.out.println("deep of calling = "+count); e.printStackTrace(); } } } |
執行引數:
-Xss128K
輸出結果:
deep of calling = 701
java.lang.StackOverflowError
執行引數:
-Xss256K
輸出結果:
deep of calling = 1817
java.lang.StackOverflowError
經驗總結:
棧空間越大,呼叫層次越深,去掉區域性變數 呼叫層次可以更深
[z1]堆
[z2]新生代的記憶體狀況
[z3]總共可用空間
[z4]12288K+ 1536K
[z5]已經使用的空間
[z6]該區間在記憶體中的起始位置
[z7]該區間當前已經分配的記憶體所到的位置。
[z8]該區間最高可以申請到的記憶體的位置。就目前的情況來看,新生代的當前邊界等於最高邊界,表示新生代的記憶體已經分配完了,不能再做擴充套件了。
[z9](0x28d80000-0x27e80000)
/1024/1024=15M
[z10]伊甸園區,物件出生的地方
[z11]總共可用的空間
[z12]GC複製演算法,倖存代from區
[z13]GC複製演算法,倖存代to區,他和from區的總記憶體大小一定是相等的。這兩塊區域是用於GC收集的複製演算法的。這兩塊區域,只有一塊是可用的,另一塊是為複製演算法準備的。互為備用,每次GC之後,相互切換角色。
[z14]老年代的記憶體的總體狀況
[z15]永久區(方法區)的記憶體狀況。Jdk5.0之後,會有一個共享區間,一些基礎的java類會被載入到這個共享區間,供所有的jvm虛擬機器使用。所以這裡方法區被佔用的空間不大。只有142k。
[z16]只讀共享區間記憶體情況
[z17]可讀可寫共享區間記憶體情況。一些基礎類主要是載入到了這兩個共享區間,所以它們記憶體被使用率比較高。
[z18]呼叫0次GC的時候
[z19]GC的情況
[z20]呼叫1次GC的時候
[z21]老鍵盤在ESC行最右邊,新鍵盤在方向鍵那塊右上角,多媒體鍵盤和筆記本可能沒有。用ctrl+c或
Esc替代。
[z22]%p代表的是當前這個java程式的pid,也就是程序id
轉載於:https://my.oschina.net/kangxi/blog/1822637