1. 程式人生 > >JVM--心得 堆棧區域和GC的設置

JVM--心得 堆棧區域和GC的設置

src agen ren epg inter 比較 心得 for 調整

簡單記錄JVM存儲空間的幾大模塊的常用名稱;使用哪些參數對各個模塊進行尺寸設置及垃圾回收;最後舉例子說明下參數配置後的GC的效果。

第一步,首先對於存儲的幾大模塊進行一下簡單描述:
1)JVM的內存分為兩塊:A.堆heap B.非堆non-heap:即堆以外的棧、方法區、常量池、寄存器空間(稱為PermanateGeneration持久代)
2)然後堆heap分為YongGeneration年輕代,TenuringGeneration年老代。
3) YongGeneration又分為Eden區,Survivor區(Survivor有兩個區)
各個區域的作用,可以參看“JVM--心得概念”隨筆裏的記述內容。日常使用時,主要關註Heap這一最大的內存空間。持久代主要存儲元數據和靜態數據,不用過多的定制。

第二步,針對空間分配和垃圾回收引入如下參數的設置(使用Eclipse時,可以通過exclipse.ini文件或者設定的JRE缺省參數設置。tomcat時catalina裏可以設置。直接用JRE時,通過控制臺命令進行設置。)

主要參數:
1)空間大小相關的設定:
-Xmx 該參數規定了JVM堆的最大內存空間。例子:-Xmx512M
-Xms 該參數規定了JVM堆的初始內存尺寸。例子:-Xmx512M
當堆的使用>=堆空間當前空間的60%時,JVM會增大當前堆的內存空間,最大為-Xmx。
當堆的使用<=堆空間當前空間的30%時,JVM會減少當前堆的內存空間,最小為-Xms。
為了避免GC後頻繁調整當前堆空間的大小,所以可以把-Xmx和-Xms設置為相同的值。
-Xmn 該參數規定了年輕代的空間。即Eden和兩個Survivor的區域總空間。例子:-Xmn128M。官方推薦該尺寸設置為堆空間的3/8。
-Xss 該參數規定了單線程Java棧的大小。理論上該參數越小,可以使用的Java線程越多,實際情況線程不會無限多。例子:-Xss1M或者Xss128K
-XX:MaxPermSize 該參數規定了持久代的最大空間。例子:-XX:MaxPermSize=64M

2)空間比率劃分的設定:
-XX:NewRatio 該參數規定了年輕代和年老代的比率。當-XX:NewRatio=4時,代表的含義為 年輕代:年老代=1:4
-XX:SurvivorRatio 該參數規定了Servior和Eden的比率。當-XX:SurvivorRatio=4時,代表的含義為 Servier:Eden=2:4。
因為Survivor有兩個區域,所以這裏是2:4。可以當成Survivor是雙胞胎,打架一起上。

3)GC有關的參數:
-XX:+UseParNewGC 聲明了年輕代使用並行收集策略。(還有UseSerialGC串行GC策略,適合單線程程序,服務器應用很少使用)
-XX:+UseConcMarkSweepGC 聲明了年老代使用並發收集策略(簡稱CMS,GC日誌中經常出現該單詞)。並發收集策略比較註重回收的效率,減少程序暫停的時間。
-XX:ParallelGCTheads 聲明了並發回收時,參與工作的線程數量。一般和處理器的個數相等。例子:-XX:ParallelGCTheads=4
-XX:CMSInitiatingOccupancyFraction 聲明了當年老代的使用率超過該比率時,對年老代進行GC。避免年老代空間不足引發FullGC。

例子:- XX:CMSInitiatingOccupancyFraction=60
-XX:CMSFullGCsBeforeCompaction 聲明了當發生了一定次數的FullGc後實施內存的碎片整理。比如當發生ParNew即年輕代的GC時,不一定是空余空間不足,
可能由於內存的碎片導致連續的可用內存空間不足。實施碎片整理本身會占用性能,整理的頻率需要按實際情況設定。例子 -XX:CMSFullGCsBeforeCompaction=4
說名:上述設置主要是面向並發回收策略中的常用參數。還有其他的策略參數(如並行回收策略)請參看官方文檔。

4)GC的信息查看
-XX:+PrintGC 聲明了打印GC信息
-XX:+PrintGCDetails 聲明了打印GC的詳細信息
-Xloggc 聲明了把GC的信息出力到指定文件中。例子:-Xloggc:D:\work\chongpf\workspace\skillDoc\JVM\Capter3_parameter\jvmgc.log

第三步,實際應用測試一下。
1)配置:本例按eclipse舉例。通過窗口->設定->Java->安裝的JRE->選擇目前的JRE,並按編輯按鈕->默認的JVM參數裏輸入如下內容(填入時,不要換行):
-Xmx512M -Xms512M -Xmn128M -Xss1M -XX:NewRatio=3 -XX:SurvivorRatio=2 -XX:PermSize=64M -XX:MaxPermSize=64M -XX:+UseParNewGC - XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=4 -XX:CMSInitiatingOccupancyFraction=20 -XX:CMSFullGCsBeforeCompaction=4 -XX:+PrintGC -XX:+PrintGCDetails -j avaagent:D:\work\chongpengfei\src\outlib\sizeOf.jar -Xloggc:D:\work\chongpengfei\workspace\skillDoc\JVM\Capter3_parameter\jvmgc.log

另外,調試時為了方便查看對象的尺寸,工程裏引入了SizeOf的jar包。並把該jar設置到了Jvm的啟動參數中。
下載路徑:https://sourceforge.net/projects/sizeof/

2)代碼如下:
-------------------------------------------------------------------------------
package com.chong.studyparalell.jvm.heap;

import java.util.Date;
import net.sourceforge.sizeof.SizeOf;

public class HeapDemo {

public static void main(String [] args){
HeapDemo demo = new HeapDemo();
demo.testJVMParamAndGC();
}

private void testJVMParamAndGC(){

for(int i=0;i<1000;i++){

//每次生成一個4M的數組,測試Eden區域和Survivior區域,即:new generation
int[] temp = new int[1*1024*1024];
System.out.println(new Date().toString()+ " pintSize:" + SizeOf.humanReadable(SizeOf.deepSizeOf(temp)));

// 每循環100次,新建一個80M大小的數組引發CMS GC使用,即 tenuringGeneration
if(i%100==0 && i>0){
int[] intArr = new int[20*1024*1024];
System.out.println(new Date().toString()+ " pintSize:" + SizeOf.humanReadable(SizeOf.deepSizeOf(intArr)));
}
}

//最後測試一下FullGC
System.gc();
}
}
-------------------------------------------------------------------------------
控制臺的部分消息:
Found big object: [[email protected] size: 4.0000152587890625Mb
Fri Oct 13 18:20:25 CST 2017 pintSize:4.0000152587890625Mb
Found big object: [[email protected] size: 4.0000152587890625Mb
Fri Oct 13 18:20:25 CST 2017 pintSize:4.0000152587890625Mb
Found big object: [[email protected] size: 4.0000152587890625Mb
Fri Oct 13 18:20:25 CST 2017 pintSize:4.0000152587890625Mb
Found big object: [[email protected] size: 4.0000152587890625Mb
Fri Oct 13 18:20:25 CST 2017 pintSize:4.0000152587890625Mb
Found big object: [[email protected] size: 4.0000152587890625Mb
Fri Oct 13 18:20:25 CST 2017 pintSize:4.0000152587890625Mb
=>取到了1*1024*1024數組的大小為4M。
-------------------------------------------------------------------------------
GClog的部分內容如下:
0.298: [GC 0.298: [ParNew: 65375K->711K(98304K), 0.0050990 secs] 65375K->711K(491520K), 0.0051687 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
0.316: [GC 0.316: [ParNew: 64144K->895K(98304K), 0.0045324 secs] 64144K->895K(491520K), 0.0045901 secs] [Times: user=0.05 sys=0.00, real=0.00 secs]
0.332: [GC 0.332: [ParNew: 63451K->917K(98304K), 0.0029476 secs] 63451K->917K(491520K), 0.0030049 secs] [Times: user=0.06 sys=0.00, real=0.00 secs]
0.346: [GC 0.346: [ParNew: 62652K->999K(98304K), 0.0030507 secs] 62652K->999K(491520K), 0.0031118 secs] [Times: user=0.05 sys=0.02, real=0.00 secs]
0.360: [GC 0.360: [ParNew: 63073K->1020K(98304K), 0.0045439 secs] 63073K->1020K(491520K), 0.0046042 secs] [Times: user=0.05 sys=0.00, real=0.00 secs]
0.373: [GC 0.373: [ParNew: 62588K->1025K(98304K), 0.0039508 secs] 62588K->1025K(491520K), 0.0040171 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.432: [GC 0.432: [ParNew: 62550K->1027K(98304K), 0.0038388 secs] 144470K->82947K(491520K), 0.0038931 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.436: [GC [1 CMS-initial-mark: 81920K(393216K)] 87043K(491520K), 0.0006483 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.437: [CMS-concurrent-mark-start]
0.452: [GC 0.452: [ParNew: 62577K->1027K(98304K), 0.0035159 secs] 144497K->82947K(491520K), 0.0035706 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.461: [CMS-concurrent-mark: 0.020/0.024 secs] [Times: user=0.05 sys=0.02, real=0.02 secs]
0.461: [CMS-concurrent-preclean-start]
0.462: [CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.462: [CMS-concurrent-abortable-preclean-start]
0.465: [GC 0.465: [ParNew: 62541K->1027K(98304K), 0.0029296 secs] 144461K->82947K(491520K), 0.0029711 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.477: [GC 0.477: [ParNew: 62830K->1027K(98304K), 0.0029403 secs] 144750K->82947K(491520K), 0.0029839 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.480: [CMS-concurrent-abortable-preclean: 0.011/0.018 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
0.481: [GC[YG occupancy: 5123 K (98304 K)]0.481: [Rescan (parallel) , 0.0012978 secs]0.482: [weak refs processing, 0.0000056 secs]0.482: [scrub string table, 0.0000582 secs] [1 CMS-remark: 81920K(393216K)] 87043K(491520K), 0.0014650 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.482: [CMS-concurrent-sweep-start]
0.482: [CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.482: [CMS-concurrent-reset-start]
0.485: [CMS-concurrent-reset: 0.003/0.003 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
中間省略
1.187: [GC 1.187: [ParNew: 41003K->4096K(98304K), 0.0033611 secs]1.191: [CMS1.191: [CMS-concurrent-abortable-preclean: 0.006/0.053 secs] [Times: user=0.12 sys=0.00, real=0.05 secs]
(concurrent mode failure) (concurrent mode failure)[YG occupancy: 4096 K (98304 K)]1.191: [Rescan (parallel) , 0.0004875 secs]1.191: [weak refs processing, 0.0000038 secs]1.191: [scrub string table, 0.0000466 secs]: 328370K->690K(393216K), 0.0033748 secs] 369374K->4786K(491520K), [CMS Perm : 2526K->2526K(65536K)], 0.0068582 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
1.208: [GC 1.208: [ParNew: 65605K->0K(98304K), 0.0036942 secs] 148215K->82610K(491520K), 0.0037520 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.212: [GC [1 CMS-initial-mark: 82610K(393216K)] 86706K(491520K), 0.0000757 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.213: [CMS-concurrent-mark-start]
1.221: [GC 1.221: [ParNew: 61504K->0K(98304K), 0.0037417 secs] 144115K->82610K(491520K), 0.0037896 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
1.232: [CMS-concurrent-mark: 0.015/0.019 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
1.232: [CMS-concurrent-preclean-start]
1.233: [CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.233: [CMS-concurrent-abortable-preclean-start]
1.235: [GC 1.235: [ParNew: 61504K->0K(98304K), 0.0024883 secs] 144115K->82610K(491520K), 0.0025358 secs] [Times: user=0.06 sys=0.00, real=0.00 secs]
1.246: [GC 1.246: [ParNew: 61504K->0K(98304K), 0.0019179 secs] 144115K->82610K(491520K), 0.0019619 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.257: [GC 1.257: [ParNew: 61504K->0K(98304K), 0.0019337 secs] 144115K->82610K(491520K), 0.0019807 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.267: [GC 1.267: [ParNew: 61504K->0K(98304K), 0.0029792 secs] 144115K->82610K(491520K), 0.0030211 secs] [Times: user=0.05 sys=0.00, real=0.00 secs]
1.286: [GC 1.286: [ParNew: 61509K->0K(98304K), 0.0017768 secs] 226039K->164530K(491520K), 0.0018204 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.297: [GC 1.297: [ParNew: 61504K->0K(98304K), 0.0041082 secs] 226035K->164530K(491520K), 0.0041561 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
1.311: [GC 1.311: [ParNew: 61504K->0K(98304K), 0.0034766 secs] 226035K->164530K(491520K), 0.0035283 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.322: [GC 1.322: [ParNew: 61504K->0K(98304K), 0.0026329 secs] 226035K->164530K(491520K), 0.0027009 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.334: [GC 1.334: [ParNew: 61504K->0K(98304K), 0.0023160 secs] 226035K->164530K(491520K), 0.0023660 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.344: [GC 1.344: [ParNew: 61504K->0K(98304K), 0.0019123 secs] 226035K->164530K(491520K), 0.0019568 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.354: [GC 1.354: [ParNew: 61504K->0K(98304K), 0.0016707 secs] 226035K->164530K(491520K), 0.0017122 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1.358: [Full GC (System) 1.358: [CMS1.358: [CMS-concurrent-abortable-preclean: 0.016/0.125 secs] [Times: user=0.25 sys=0.00, real=0.13 secs]
(concurrent mode interrupted): 164530K->686K(393216K), 0.0098896 secs] 180933K->686K(491520K), [CMS Perm : 2526K->2523K(65536K)], 0.0099431 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
Heap
par new generation total 98304K, used 1310K [0x04a60000, 0x0ca60000, 0x0ca60000)
eden space 65536K, 2% used [0x04a60000, 0x04ba7b48, 0x08a60000)
from space 32768K, 0% used [0x0aa60000, 0x0aa60000, 0x0ca60000)
to space 32768K, 0% used [0x08a60000, 0x08a60000, 0x0aa60000)
concurrent mark-sweep generation total 393216K, used 686K [0x0ca60000, 0x24a60000, 0x24a60000)
concurrent-mark-sweep perm gen total 65536K, used 2528K [0x24a60000, 0x28a60000, 0x28a60000)
------------------------------------------------------------------------
如何讀GC的日誌呢,其實有規律的,一般可以按下面理解
ParNew:全稱 Parallel New 指年輕代的並行回收結果。範式: “年輕代GC前->年輕代GC後(年輕代總空間),花費時間m.n秒。”
CMS:全稱 Concurent Mark Sweep 指年老代,持久代的並發回收處理。
主要有幾個生命周期,如CMS-initial-mark,CMS-concurrent-mark-start,CMS-concurrent-mark,CMS-concurrent-preclean-start,
CMS-concurrent-preclean,CMS-concurrent-abortable-preclean-start,CMS-concurrent-abortable-preclean,CMS-remark
這幾個沒有使用略稱還是比較容易理解它們的動作的。其中第一個和最後一個會stopWorld,需要主要它們的花費時間。
GC/FullGC:涵蓋年輕代/年老代/持久代回收結果,以及耗費的時間。

Heap:堆的詳細信息
par new generation 新生代信息
eden space Eden區域
from space Survivor的第1個區域
to space Survivor的第2個區域
concurrent mark-sweep 年老代信息
concurrent-mark-sweep 持久代信息
最後對Survivor的from和to的兩個區域補充一下說明:
當Eden第一次滿了之後,會把Eden活著的對象copy到from區域,然後清空Eden區域。
當Eden第二次滿了之後,會把Eden活著的對象+from區域的對象,一起copy到to區域,然後清空Eden區域。
copy的過程中會保證對象的使用內存是連續的。
當Eden第N次滿了時,會來對from或者to的Survivor區域再一次的進行乾坤大挪移。
部分對象命比較長,copy到一定次數還沒死,就會被挪移到老生代的Tenuring區中。

參看Link

http://unixboy.iteye.com/blog/174173/
http://www.jianshu.com/p/2fdee831ed03

JVM--心得 堆棧區域和GC的設置