1. 程式人生 > 實用技巧 >常用的JVM配置引數

常用的JVM配置引數

>>> hot3.png

常用JVM配置引數

大綱:

n Trace(軌跡/痕跡)跟蹤引數

n 堆的分配引數

n 棧的分配引數

Trace跟蹤引數

-verbose:gc

java -verbose:gc 中引數-verbose:gc 表示輸出虛擬機器中GC的詳細情況.

使用後輸出如下:

[Full GC 168K->97K(1984K), 0.0253873 secs]

解讀如下:

箭頭前後的資料168K97K分別表示垃圾收集GC前後所有存活物件使用的記憶體容量,說明168K-97K=71K的物件容量被回收,括號內的資料1984K為堆記憶體的總容量收集所需要的時間是0.0253873

(這個時間在每次執行的時候會有所不同)

-XX:+printGC

可以列印GC的簡要資訊

– [GC 4790K->374K(15872K), 0.0001606 secs]

4790KGC前堆被使用的容量

374KGC後堆被使用的容量

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資訊

4416KGC之前,新生代被使用的記憶體大小

0KGC之後,新生代被使用的記憶體大小

4928K:新生代的總記憶體大小

0.0001897 secs:新生代GC垃圾收集花費的時間

4790KGC之前堆中總共被使用的記憶體大小

374KGC之後堆中總共被使用的記憶體大小

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的日誌輸出都是在控制檯的)

– 幫助開發人員分析問題

162008_siqY_3512041.png

-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

日誌列印:

162135_BUTz_3512041.png

結果分析

  1. 沒有觸發GC
  2. 全部分配在老年代

-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

日誌列印:

162150_Q3ng_3512041.png

實際佔用空間大約10M 因為有系統級別的物件 如ClassLoader Thread等

結果分析:

  1. 沒有觸發GC
  2. 全部分配在eden
  3. 老年代沒有使用

-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

日誌列印:

162207_c6Cv_3512041.png

一共回收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

日誌列印:

162218_izJ9_3512041.png

回收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

日誌列印:

162230_NSuE_3512041.png

結果分析:

比例分配,新生代 老年代對半開

物件全部留在新生代

-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

日誌列印:

162244_GlN0_3512041.png

結果分析:

減少了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]);

162254_uIrQ_3512041.png

檢視匯出的堆檔案:

162304_O5lz_3512041.png

-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());//不斷產生新的類

}

檢視日誌:

162326_6ueM_3512041.png

分析導致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