1. 程式人生 > >記一次IDEA編譯器調優

記一次IDEA編譯器調優

str out style its sun 復制算法 dsc this max

前言:

我們知道,IDEA是用Java寫的,那麽他肯定也存在虛擬機的調優的問題,那麽今天我們就對它進行開刀。

下面是默認參數 位置在:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2\bin\idea64.exe.vmoptions

 1 -Xms128m
 2 -Xmx756m
 3 -XX:ReservedCodeCacheSize=240m
 4 -XX:+UseConcMarkSweepGC
 5 -XX:SoftRefLRUPolicyMSPerMB=50
 6 -ea
 7 -Dsun.io.useCanonCaches=false
8 -Djava.net.preferIPv4Stack=true 9 -Djdk.http.auth.tunneling.disabledSchemes="" 10 -XX:+HeapDumpOnOutOfMemoryError 11 -XX:-OmitStackTraceInFastThrow

我們從這裏可以看到,堆最小分配了128M,最大分配了756M。

新生代用的是ParNew收集器,基於標記復制算法

老年代用的是CMS,基於標記清除算法。

優化前:

我們這裏用到了兩個神器。jvisualvm.exe和jconsole.exe。

我們先啟動一下IDEA

技術分享圖片

新生代進行了56次gc,老年代進行了5次Full gc。這肯定不能忍受的嘛。

優化一:

 1 -Xms1024m
 2 -Xmx1024m
 3 -Xmn350m
 4 -XX:ReservedCodeCacheSize=240m
 5 -XX:+UseConcMarkSweepGC
 6 -XX:SoftRefLRUPolicyMSPerMB=50
 7 -ea
 8 -Dsun.io.useCanonCaches=false
 9 -Djava.net.preferIPv4Stack=true
10 -Djdk.http.auth.tunneling.disabledSchemes=""
11
-XX:+HeapDumpOnOutOfMemoryError 12 -XX:-OmitStackTraceInFastThrow 13 14 -verbose:gc 15 -XX:+PrintGCDetails 16 -XX:+PrintGCDateStamps 17 -Xloggc:gcc.log

設置堆的最大最小都為1024M,不給動態擴容。並且設置新生代為350M,同時打出日誌。

技術分享圖片

可以看到,只進行了7次新生代GC,3次老年代GC。

我很奇怪,為何老年代沒有填滿,並且還有好多空間,會發生三次FullGC呢?部分日誌如下:

 1 2018-08-20T22:35:57.399+0800: 3.963: [CMS-concurrent-preclean-start]
 2 2018-08-20T22:35:57.399+0800: 3.965: [CMS-concurrent-preclean: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
 3 2018-08-20T22:35:57.399+0800: 3.965: [CMS-concurrent-abortable-preclean-start]
 4 2018-08-20T22:35:59.457+0800: 6.018: [CMS-concurrent-abortable-preclean: 1.465/2.053 secs] [Times: user=6.16 sys=0.52, real=2.06 secs] 
 5 2018-08-20T22:35:59.458+0800: 6.019: [GC (CMS Final Remark) [YG occupancy: 167766 K (322560 K)]2018-08-20T22:35:59.458+0800: 6.019: [Rescan (parallel) , 0.0669837 secs]2018-08-20T22:35:59.525+0800: 6.086: [weak refs processing, 0.0000425 secs]2018-08-20T22:35:59.525+0800: 6.086: [class unloading, 0.0054995 secs]2018-08-20T22:35:59.530+0800: 6.091: [scrub symbol table, 0.0064731 secs]2018-08-20T22:35:59.537+0800: 6.098: [scrub string table, 0.0004637 secs][1 CMS-remark: 0K(690176K)] 167766K(1012736K), 0.0803359 secs] [Times: user=0.25 sys=0.00, real=0.08 secs] 
 6 2018-08-20T22:35:59.538+0800: 6.099: [CMS-concurrent-sweep-start]
 7 2018-08-20T22:35:59.538+0800: 6.099: [CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
 8 2018-08-20T22:35:59.538+0800: 6.099: [CMS-concurrent-reset-start]
 9 2018-08-20T22:35:59.540+0800: 6.101: [CMS-concurrent-reset: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
10 2018-08-20T22:36:03.352+0800: 9.915: [GC (Allocation Failure) 2018-08-20T22:36:03.352+0800: 9.915: [ParNew: 310560K->29155K(322560K), 0.0792661 secs] 310560K->47946K(1012736K), 0.0793506 secs] [Times: user=0.25 sys=0.02, real=0.08 secs] 
11 2018-08-20T22:36:07.438+0800: 14.013: [GC (CMS Initial Mark) [1 CMS-initial-mark: 18790K(690176K)] 255956K(1012736K), 0.0418642 secs] [Times: user=0.22 sys=0.00, real=0.06 secs] 
12 2018-08-20T22:36:07.515+0800: 14.076: [CMS-concurrent-mark-start]

因為老年代是采用CMS,我們來分析下,什麽情況下CMS會導致FullGC。

1:擔保失敗,即在並發清除,會有新生代擔保進來,如果不足,則提前出發Full GC。

可通過 -XX:CMSInitiatingOccupancyFraction 來調整比例。

2:因為CMS是標記清除算法,勢必會產生大量的碎片,導致Full GC

可通過調整老年代的大小來進行避免。

但經過上面兩個分析,並進行了調整,發覺仍然會發生FullGC,並且老年代的空間還剩余特別的多,根本不存在空間不足,或者找不到連續空間的問題,那麽為何還會進行Full GC呢。

優化二:

 1 -Xms1024m
 2 -Xmx1024m
 3 -Xmn350m
 4 -XX:ReservedCodeCacheSize=240m
 5 -XX:+UseConcMarkSweepGC
 6 -XX:SoftRefLRUPolicyMSPerMB=50
 7 -ea
 8 -Dsun.io.useCanonCaches=false
 9 -Djava.net.preferIPv4Stack=true
10 -Djdk.http.auth.tunneling.disabledSchemes=""
11 -XX:+HeapDumpOnOutOfMemoryError
12 -XX:-OmitStackTraceInFastThrow
13 
14 -verbose:gc
15 -XX:+PrintGCDetails
16 -XX:+PrintGCDateStamps
17 -Xloggc:gcc.log
18 
19 -XX:MetaspaceSize=1024m

註意看最後一個參數-XX:MetaspaceSize=1024M

技術分享圖片

可以看到,此時一次FullGC都沒有發生,新生代GC至發生了7次就已經完成了啟動。

結論:

測試,我測試了好多遍,當然不會像博客這樣簡單的測試。差了好多資料,比了好多的數據。

優化前,大概啟動進行50多次新生代GC,3-5次老年代GC。

優化後,進行7次左右新生代GC,0次老年代GC。

啟動時間大概快了有10s。

分析一下為何,MetaSpaceGC 會引發一次CMS GC

 1 JDK8: Metaspace 
 2 In JDK 8, classes metadata is now stored in the native heap 
 3 and this space is called Metaspace. There are some new flags added for 
 4 Metaspace in JDK 8: 
 5 -XX:MetaspaceSize= where is the initial amount of space(the initial 
 6 high-water-mark) allocated for class metadata (in bytes) that may induce a 
 7 garbage collection to unload classes. The amount is approximate. After the 
 8 high-water-mark is first reached, the next high-water-mark is managed by 
 9 the garbage collector 
10 -XX:MaxMetaspaceSize= where is the maximum amount of space to be allocated for class 
11 metadata (in bytes). This flag can be used to limit the amount of space 
12 allocated for class metadata. This value is approximate. By default there 
13 is no limit set. 
14 -XX:MinMetaspaceFreeRatio= where is the minimum percentage of class metadata capacity 
15 free after a GC to avoid an increase in the amount of space 
16 (high-water-mark) allocated for class metadata that will induce a garbage collection. 
17 -XX:MaxMetaspaceFreeRatio= where is the maximum percentage of class metadata capacity 
18 free after a GC to avoid a reduction in the amount of space 
19 (high-water-mark) allocated for class metadata that will induce a garbage collection. 
20 By default class 
21 metadata allocation is only limited by the amount of available native memory. We 
22 can use the new option MaxMetaspaceSize to limit the amount of native memory 
23 used for the class metadata. It is analogous(類似) to MaxPermSize. A garbage collection is induced to collect the dead classloaders 
24 and classes when the class metadata usage reaches MetaspaceSize (12Mbytes on 
25 the 32bit client VM and 16Mbytes on the 32bit server VM with larger sizes on 
26 the 64bit VMs). Set MetaspaceSize to a higher value to delay the induced 
27 garbage collections. After an induced garbage collection, the class metadata usage 
28 needed to induce the next garbage collection may be increased.

JVM規範中運行時數據區域中的方法區,在HotSpot虛擬機中又被習慣稱為永生代或者永生區,Permanet Generation中存放的為一些class的信息、常量、靜態變量等數據,當系統中要加載的類、反射的類和調用的方法較多時,Permanet Generation可能會被占滿,在未配置為采用CMS GC的情況下也會執行Full GC。如果經過Full GC仍然回收不了,那麽JVM會拋出如下錯誤信息:java.lang.OutOfMemoryError: PermGen space 為避免Perm Gen占滿造成Full GC現象,可采用的方法為增大Perm Gen空間或轉為使用CMS GC。

即如果MetaSpace不足,也會觸發Full GC(在64為機器上默認20.8M)。那麽調大即可,延遲Full GC的時間。

參考資料:

https://blog.csdn.net/liubenlong007/article/details/78143285

http://tech.dianwoda.com/2018/01/10/jdk8-de-fullgc-zhi-metaspace/

記一次IDEA編譯器調優