JVM參數以及用法


工作以后,發覺真的幾乎沒有像大學那樣空閑的時間,坐下來看看書寫寫博客了。最近的一篇博客距離現在已經近一個多月了,最近也在復習Java的東西,准備校招,看了看JVM的東西,就當作記筆記。

(一)JVM參數:

  • 第一類包括了標准參數。顧名思義,標准參數中包括功能和輸出的參數都是很穩定的,很可能在將來的 JVM 版本中不會改變。你可以用 java 命令(或者是用 java -help)檢索出所有標准參數。我們在第一部分中已經見到過一些標准參數,例如:-server。
  • 第二類是 X 參數,非標准化的參數在將來的版本中可能會改變。所有的這類參數都以 - X 開始,並且可以用 java -X 來檢索。注意,不能保證所有參數都可以被檢索出來,其中就沒有 - Xcomp。
  • 第三類是包含 XX 參數(到目前為止最多的),它們同樣不是標准的,甚至很長一段時間內不被列出來(最近,這種情況有改變 ,我們將在本系列的第三部分中討論它們)。然而,在實際情況中 X 參數和 XX 參數並沒有什么不同。X 參數的功能是十分穩定的,然而很多 XX 參數仍在實驗當中(主要是 JVM 的開發者用於 debugging 和調優 JVM 自身的實現)。 

(1)-Xms20M

表示設置JVM啟動內存的最小值為20M,必須以M為單位

(2)-Xmx20M

表示設置JVM啟動內存的最大值為20M,必須以M為單位。將-Xmx和-Xms設置為一樣可以避免JVM內存自動擴展。大的項目-Xmx和-Xms一般都要設置到10G、20G甚至還要高

(3)-verbose:gc

表示輸出虛擬機中GC的詳細情況

(4)-Xss128k

表示可以設置虛擬機棧的大小為128k

(5)-Xoss128k

表示設置本地方法棧的大小為128k。不過HotSpot並不區分虛擬機棧和本地方法棧,因此對於HotSpot來說這個參數是無效的

(6)-XX:PermSize=10M

表示JVM初始分配的永久代的容量,必須以M為單位

(7)-XX:MaxPermSize=10M

表示JVM允許分配的永久代的最大容量,必須以M為單位,大部分情況下這個參數默認為64M

(8)-Xnoclassgc

表示關閉JVM對類的垃圾回收

(9)-XX:+TraceClassLoading

表示查看類的加載信息

(10)-XX:+TraceClassUnLoading

表示查看類的卸載信息

(11)-XX:NewRatio=4

表示設置年輕代:老年代的大小比值為1:4,這意味着年輕代占整個堆的1/5

(12)-XX:SurvivorRatio=8

表示設置2個Survivor區:1個Eden區的大小比值為2:8,這意味着Survivor區占整個年輕代的1/5,這個參數默認為8

(13)-Xmn20M

表示設置年輕代的大小為20M

(14)-XX:+HeapDumpOnOutOfMemoryError

表示可以讓虛擬機在出現內存溢出異常時Dump出當前的堆內存轉儲快照

(15)-XX:+UseG1GC

表示讓JVM使用G1垃圾收集器

(16)-XX:+PrintGCDetails

表示在控制台上打印出GC具體細節

(17)-XX:+PrintGC

表示在控制台上打印出GC信息

(18)-XX:PretenureSizeThreshold=3145728

表示對象大於3145728(3M)時直接進入老年代分配,這里只能以字節作為單位

(19)-XX:MaxTenuringThreshold=1

表示對象年齡大於1,自動進入老年代

(20)-XX:CompileThreshold=1000

表示一個方法被調用1000次之后,會被認為是熱點代碼,並觸發即時編譯

(21)-XX:+PrintHeapAtGC

表示可以看到每次GC前后堆內存布局

(22)-XX:+PrintTLAB

表示可以看到TLAB的使用情況

(23)-XX:+UseSpining

開啟自旋鎖

(24)-XX:PreBlockSpin

更改自旋鎖的自旋次數,使用這個參數必須先開啟自旋鎖


 

 

(二)用法實例:

 

 1 import java.util.Date;
 2 import java.util.concurrent.TimeUnit;
 3 
 4 public class Main {
 5     public static final int MB = 1024 * 1024;
 6     public static void main(String[] args) throws InterruptedException {
 7 
 8         TimeUnit.SECONDS.sleep(20);
 9         byte[] b1, b2, b3, b4;
10         b1 = new byte[2 * MB];
11         System.out.println("第一個2M分配完畢 time = " + new Date());
12         TimeUnit.SECONDS.sleep(5);
13         b2 = new byte[2 * MB];
14         System.out.println("第二個2M分配完畢 time = " + new Date());
15         TimeUnit.SECONDS.sleep(5);
16         b3 = new byte[2 * MB];
17         System.out.println("第三個2M分配完畢 time = " + new Date());
18         TimeUnit.SECONDS.sleep(5);
19         b4 = new byte[2 * MB];
20         System.out.println("第四個2M分配完畢 time = " + new Date());
21         TimeUnit.SECONDS.sleep(10);
22     }
23 }

 

 

JVM的參數設置如下:  -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8

Xms最小堆,Xmx最大堆都設置為了20M。Xmn年輕代設置為了10M,那么老年代也為10M,SurvivorRatio年輕帶的Eden和Survivor的比值為8:1:1。

 

2 [GC (Allocation Failure) [PSYoungGen: 8192K->1008K(9216K)] 8192K->1648K(19456K), 0.0012271 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
 3 [GC (Allocation Failure) [PSYoungGen: 7446K->1016K(9216K)] 8086K->2352K(19456K), 0.0016344 secs] [Times: user=0.13 sys=0.00, real=0.00 secs] 
 4 第一個2M分配完畢 time = Sun Jul 29 16:00:40 CST 2018
 5 第二個2M分配完畢 time = Sun Jul 29 16:00:45 CST 2018
 6 第三個2M分配完畢 time = Sun Jul 29 16:00:50 CST 2018
 7 [GC (Allocation Failure) [PSYoungGen: 8414K->1000K(9216K)] 9750K->8577K(19456K), 0.0065138 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
 8 [Full GC (Ergonomics) [PSYoungGen: 1000K->0K(9216K)] [ParOldGen: 7577K->8005K(10240K)] 8577K->8005K(19456K), [Metaspace: 9104K->8987K(1058816K)], 0.0158481 secs] [Times: user=0.13 sys=0.00, real=0.02 secs] 
 9 第四個2M分配完畢 time = Sun Jul 29 16:00:55 CST 2018
10 Heap
11  PSYoungGen      total 9216K, used 2921K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
12   eden space 8192K, 35% used [0x00000000ff600000,0x00000000ff8da738,0x00000000ffe00000)
13   from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
14   to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
15  ParOldGen       total 10240K, used 8005K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
16   object space 10240K, 78% used [0x00000000fec00000,0x00000000ff3d15f8,0x00000000ff600000)
17  Metaspace       used 9046K, capacity 9256K, committed 9600K, reserved 1058816K
18   class space    used 1060K, capacity 1117K, committed 1152K, reserved 1048576K
19 
20 Process finished with exit code 0

 

 

 

 

 分析如下:

 第二,第三行可能是  TimeUnit.SECONDS.sleep(20); 這個占了內存,導致內存不足,然后就進行了兩次年輕代GC,主要是為了看jconsole的那兩幅圖。

分配了三個2M以后,發覺eden區不夠位置了,此時進行了年輕代的GC,但是 擔保失敗了 GC (Allocation Failure)。可能在老年代沒有找到連續的內存,所以擔保失敗后,進行了一次full gc。

我們看jconsole上面的兩幅圖片,在16:01前面,Eden區突然下降,Old區突然上升。說明full gc將Eden區的三個2M的全部放到了Old區。然后將第四個2M的放到了Eden區。

所以最后,Eden區分配了一個b4,Old區分配了b1,b2,b3三個。看日志也可以看出來。

 

下來我們修改下參數,避免它進行full gc,畢竟full gc是不太好的。 

-verbose:gc -Xms110M -Xmx110M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8

我們將老年代調到100M,你會發覺就不會進行full gc了,因為擔保成功了。所以新生代,老年代最好的比列,並不是1:1,而是老年代站絕大多數,畢竟新生代 “死的快”。

 

最近接觸到的JVM參數僅限於這幾個,工具用的也就是jps,jconsole,不是特別的多。所以這里就舉了一個例子出來。但這個例子的很好的說明了,如何避免Full GC

Full GC發生大概有以下幾種情況:

1:老年代不足,比如上面的full gc。新生代的對象不能全部進入老年代,即擔保失敗,那么就行一次full gc。同理大對象直接進入老年代,也可能進行full gc

2:CMS垃圾回收器。CMS因為采用的標記清除算法,所以很容易產生大量的碎片,所以full gc特別容易。還有一種就是CMS是一種並發清理垃圾的,在並發清理的過程,有對象進入,但空間不足,也會造成一次full gc。可能通過調參來避免,比如調到老年代用到了90%,85%等進行cms收集來避免。

 

自己本人由於是學生,實戰經驗比較少,對JVM理解也不是特別的深入,如有錯誤,還希望各位大神能指出。大家一同學習進步。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM