❶ java內存查看與分析
業界有很多強大的java profile的工具,比如Jporfiler,yourkit,這些收費的東西我就不想說了,想說的是,其實java自己就提供了很多內存監控的小工具,下面列舉的工具只是一小部分,仔細研究下扒陵jdk的工具,還是蠻有意思的呢:)
1:gc日誌輸出
在jvm啟動參數中加入 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimestamps -XX:+PrintGCApplicationStopedTime,jvm將會按照這些參數順序輸出gc概要信息,詳細信息,gc時間信息,gc造成的應用暫停時間。如果在剛才的參數後面加入參數 -Xloggc:文件路徑,gc信息將會輸出到指定的文件中。其他參數還有
-verbose:gc和-XX:+PrintTenuringDistribution等。
2:jconsole
jconsole是jdk自帶的一個內存分析工具,它提供了圖形界面。可以查看到被監控的jvm的內存信息,線程信息,類載入信息,MBean信息。
jconsole位於jdk目錄下的bin目錄,在windows下是jconsole.exe,在unix和linux下是jconsole.sh,jconsole可以監控本地應用,也可以監控遠程應用。 要監控本地應用,執行jconsole pid,pid就是運行的java進程id,如果不帶上pid參數,則執行jconsole命令後,會看到一個對話框彈出,上面列出了本地的java進程,可以選擇一個進行監控。如果要遠程監控,則要在遠程伺服器的jvm參數里加入一些東西,因為jconsole的遠程監控基於jmx的,關於jconsole詳細用法,請見專門介紹jconsle的文章,我也會在博客里專門詳細介紹jconsole。
3:jviusalvm
在JDK6 update 7之後,jdk推出了另外一個工具:jvisualvm,java可視化虛擬機,它不但提供了jconsole類似的功能,還提供了jvm內存和cpu實時診斷,還有手動mp出jvm內存情況,手動執行gc。
和jconsole一樣,運行jviusalvm,在jdk的bin目錄下執行jviusalvm,windows下是jviusalvm.exe,linux和unix下是jviusalvm.sh。滲此租
4:jmap
jmap是jdk自帶的jvm內存分析的工具,叢兆位於jdk的bin目錄。jdk1.6中jmap命令用法:
Usage:
jmap -histo pid
(to connect to running process and print histogram of java object heap
jmap -mp:mp-options pid
(to connect to running process and mp java heap)
mp-options:
format=b binary default
file=file mp heap to file
Example: jmap -mp:format=b,file=heap.bin pid
jmap -histo pid在屏幕上顯示出指定pid的jvm內存狀況。以我本機為例,執行該命令,屏幕顯示:
num #instances #bytes class name
----------------------------------------------
1: 24206 2791864 constMethodKlass
2: 22371 2145216 [C
3: 24206 1940648 methodKlass
4: 1951 1364496 constantPoolKlass
5: 26543 1282560 symbolKlass
6: 6377 1081744 [B
7: 1793 909688 constantPoolCacheKlass
8: 1471 614624 instanceKlassKlass
9: 14581 548336 [Ljava.lang.Object;
10: 3863 513640 [I
11: 20677 496248 java.lang.String
12: 3621 312776 [Ljava.util.HashMap$Entry;
13: 3335 266800 java.lang.reflect.Method
14: 8256 264192 java.io.ObjectStreamClass$WeakClassKey
15: 7066 226112 java.util.TreeMap$Entry
16: 2355 173304 [S
17: 1687 161952 java.lang.Class
18: 2769 150112 [[I
19: 3563 142520 java.util.HashMap
20: 5562 133488 java.util.HashMap$Entry
Total 239019 17140408
為了方便查看,我刪掉了一些行。從上面的信息很容易看出,#instance指的是對象數量,#bytes指的是這些對象佔用的內存大小,class name指的是對象類型。
再看jmap的mp選項,這個選項是將jvm的堆中內存信息輸出到一個文件中,在我本機執行
jmap -mp:file=c:mp.txt 340
注意340是我本機的java進程pid,mp出來的文件比較大有10幾M,而且我只是開了tomcat,跑了一個很簡單的應用,且沒有任何訪問,可以想像,大型繁忙的伺服器上,mp出來的文件該有多大。需要知道的是,mp出來的文件信息是很原始的,絕不適合人直接觀看,而jmap -histo顯示的內容又太簡單,例如只顯示某些類型的對象佔用多大內存,以及這些對象的數量,但是沒有更詳細的信息,例如這些對象分別是由誰創建的。那這么說,mp出來的文件有什麼用呢?當然有用,因為有專門分析jvm的內存mp文件的工具。
5:jhat
上面說了,有很多工具都能分析jvm的內存mp文件,jhat就是sun jdk6及以上版本自帶的工具,位於jdk的bin目錄,執行 jhat -J -Xmx512m [file] ,file就是mp文件路徑。jhat內置一個簡單的web伺服器,此命令執行後,jhat在命令行里顯示分析結果的訪問地址,可以用-port選項指定埠,具體用法可以執行jhat -heap查看幫助信息。訪問指定地址後,就能看到頁面上顯示的信息,比jmap -histo命令顯示的豐富得多,更為詳細。
6:eclipse內存分析器
上面說了jhat,它能分析jvm的mp文件,但是全部是文字顯示,eclipse memory analyzer,是一個eclipse提供用於分析jvm 堆mp的插件,它的分析速度比jhat快,分析結果是圖形界面顯示,比jhat的可讀性更高。其實jvisualvm也可以分析mp文件,也是有圖形界面顯示的。
7:jstat
如果說jmap傾向於分析jvm內存中對象信息的話,那麼jsta就是傾向於分析jvm內存的gc情況。都是jvm內存分析工具,但顯然,它們是從不同維度來分析的。jsat常用的參數有很多,如 -gc,-gcutil,-gccause,這些選項具體作用可查看jsat幫助信息,我經常用-gcutil,這個參數的作用不斷的顯示當前指定的jvm內存的垃圾收集的信息。
我在本機執行 jstat -gcutil 340 10000,這個命令是每個10秒鍾輸出一次jvm的gc信息,10000指的是間隔時間為10000毫秒。屏幕上顯示如下信息(我只取了第一行,因為是按的一定頻率顯示,所以實際執行的時候,會有很多行):
S0 S1 E O P YGC YGCT FGC FGCT GCT
54.62 0.00 42.87 43.52 86.24 1792 5.093 33 7.670 12.763
額怎麼說呢,要看懂這些信息代表什麼意思,還必須對jvm的gc機制有一定的了解才行啊。其實如果對sun的 hot spot jvm的gc比較了解的人,應該很容易看懂這些信息,但是不清楚gc機制的人,有點莫名其妙,所以在這里我還是先講講sun的jvm的gc機制吧。說到gc,其實不僅僅只是java的概念,其實在java之前,就有很多語言有gc的概念了,gc嘛就是垃圾收集的意思,更多的是一種演算法性的東西,而跟具體語言沒太大關系,所以關於gc的歷史,gc的主流演算法我就不講了,那扯得太遠了,扯得太遠了就是扯淡。sun現在的jvm,內存的管理模型是分代模型,所以gc當然是分代收集了。分代是什麼意思呢?就是將對象按照生命周期分成三個層次,分別是:新生代,舊生代,持久代。對象剛開始分配的時候,大部分都在新生代,當新生代gc提交被觸發後了,執行一次新生代范圍內的gc,這叫minor gc,如果執行了幾次minor gc後,還有對象存活,將這些對象轉入舊生代,因為這些對象已經經過了組織的重重考驗了哇。舊生代的gc頻率會更低一些,如果舊生代執行了gc,那就是full gc,因為不是局部gc,而是全內存范圍的gc,這會造成應用停頓,因為全內存收集,必須封鎖內存,不許有新的對象分配到內存,持久代就是一些jvm期間,基本不會消失的對象,例如class的定義,jvm方法區信息,例如靜態塊。需要主要的是,新生代里又分了三個空間:eden,susvivor0,susvivor1,按字面上來理解,就是伊甸園區,倖存1區,倖存2區。新對象分配在eden區中,eden區滿時,採用標記-復制演算法,即檢查出eden區存活 的對象,並將這些對象復制到是s0或s1中,然後清空eden區。jvm的gc說開來,不只是這么簡單,例如還有串列收集,並行收集,並發收集,還有著名的火車演算法,不過那說得太遠了,現在對這個有大致了解就好。說到這里,再來看一下上面輸出的信息:
S0 S1 E O P YGC YGCT FGC FGCT GCT
54.62 0.00 42.87 43.52 86.24 1792 5.093 33 7.670 12.763
S0:新生代的susvivor0區,空間使用率為5462%
S1:新生代的susvivor1區,空間使用率為0.00%(因為還沒有執行第二次minor收集)
E:eden區,空間使用率42.87%
O:舊生代,空間使用率43.52%
P:持久帶,空間使用率86.24%
YGC:minor gc執行次數1792次
YGCT:minor gc耗費的時間5.093毫秒
FGC:full gc執行次數33
FGCT:full gc耗費的時間7.670毫秒
GCT:gc耗費的總時間12.763毫秒
怎樣選擇工具
上面列舉的一些工具,各有利弊,其實如果在開發環境,使用什麼樣的工具是無所謂的,只要能得到結果就好。但是在生產環境里,卻不能亂選擇,因為這些工具本身就會耗費大量的系統資源,如果在一個生產伺服器壓力很大的時候,貿然執行這些工具,可能會造成很意外的情況。最好不要在伺服器本機監控,遠程監控會比較好一些,但是如果要遠程監控,伺服器端的啟動腳本要加入一些jvm參數,例如用jconsloe遠程監控tomcat或jboss等,都需要設置jvm的jmx參數,如果僅僅只是分析伺服器的內存分配和gc信息,強烈推薦,先用jmap導出伺服器端的jvm的堆mp文件,然後再用jhat,或者jvisualvm,或者eclipse內存分析器來分析內存狀況。
❷ jvm 性能調優工具之 jstat 命令詳解
Jstat名稱:Java Virtual Machine statistics monitoring tool
功能描述:
Jstat是JDK自帶的一個輕量級小工具。它位於java的bin目錄下,主要利用JVM內建的指令對Java應用程序的資源和性能進行實時的命令行的監控,包括了對Heap size和垃圾回收狀況的監控。
命令用法:jstat [-命令選項] [vmid] [間隔時間/毫秒] [查詢次數]
注意:使用的jdk版本是jdk8。
C:\Users\Administrator>jstat -helpUsage: jstat -help|-options jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] Definitions: <option> An option reported by the -options option <vmid> Virtual Machine Identifier. A vmid takes the following form: <lvmid>[@<hostname>[:<port>]] Where <lvmid> is the local vm identifier for the target Java virtual machine, typically a process id; <hostname> is the name of the host running the target Java virtual machine; and <port> is the port number for the rmiregistry on the target host. See the jvmstat documentation for a more complete description of the Virtual Machine Identifier. <lines> Number of samples between header lines. <interval> Sampling interval. The following forms are allowed: <n>["ms"|"s"] Where <n> is an integer and the suffix specifies the units as milliseconds("ms") or seconds("s"). The default units are "ms". <count> Number of samples to take before terminating. -J<flag> Pass <flag> directly to the runtime system.
option:參數選項
-t:可以在列印的列加上Timestamp列,用於顯示系統運行的時間
-h:可以在周期性數據輸出的時型蠢候,指定輸出多少行以後輸出一次表頭
vmid:Virtual Machine ID( 進程的 pid)
interval:執行每次的間隔時間,單位為毫秒
count:用於指定輸出多少次記錄,預設則會一直列印
option 可以從下面參數中選擇
jstat -options
-class 用卜悄陪於查看類載入情況的統計
-compiler 用於查看HotSpot中即時編譯器編譯情運檔況的統計
-gc 用於查看JVM中堆的垃圾收集情況的統計
-gccapacity 用於查看新生代、老生代及持久代的存儲容量情況
-gcmetacapacity 顯示metaspace的大小
-gcnew 用於查看新生代垃圾收集的情況
-gcnewcapacity 用於查看新生代存儲容量的情況
-gcold 用於查看老生代及持久代垃圾收集的情況
-gcoldcapacity 用於查看老生代的容量
-gcutil 顯示垃圾收集信息
-gccause 顯示垃圾回收的相關信息(通-gcutil),同時顯示最後一次僅當前正在發生的垃圾收集的原因
-printcompilation 輸出JIT編譯的方法信息
示例:
1.-class 類載入統計
[root@hadoop ~]# jps #先通過jps獲取到java進程號(這里是一個zookeeper進程)3346 QuorumPeerMain7063 Jps[root@hadoop ~]# jstat -class 3346 #統計JVM中載入的類的數量與sizeLoaded Bytes Unloaded Bytes Time 1527 2842.7 0 0.0 1.02
Loaded:載入類的數量
Bytes:載入類的size,單位為Byte
Unloaded:卸載類的數目
Bytes:卸載類的size,單位為Byte
Time:載入與卸載類花費的時間
2.-compiler 編譯統計
[root@hadoop ~]# jstat -compiler 3346 #用於查看HotSpot中即時編譯器編譯情況的統計Compiled Failed Invalid Time FailedType FailedMethod 404 0 0 0.19 0
Compiled:編譯任務執行數量
Failed:編譯任務執行失敗數量
Invalid:編譯任務執行失效數量
Time:編譯任務消耗時間
FailedType:最後一個編譯失敗任務的類型
FailedMethod:最後一個編譯失敗任務所在的類及方法
3.-gc 垃圾回收統計
[root@hadoop ~]# jstat -gc 3346 #用於查看JVM中堆的垃圾收集情況的統計 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 128.0 128.0 0.0 128.0 1024.0 919.8 15104.0 2042.4 8448.0 8130.4 1024.0 996.0 7 0.019 0 0.000 0.019
S0C:年輕代中第一個survivor(倖存區)的容量 (位元組)
S1C:年輕代中第二個survivor(倖存區)的容量 (位元組)
S0U:年輕代中第一個survivor(倖存區)目前已使用空間 (位元組)
S1U:年輕代中第二個survivor(倖存區)目前已使用空間 (位元組)
EC:年輕代中Eden(伊甸園)的容量 (位元組)
EU:年輕代中Eden(伊甸園)目前已使用空間 (位元組)
OC:Old代的容量 (位元組)
OU:Old代目前已使用空間 (位元組)
MC:metaspace(元空間)的容量 (位元組)
MU:metaspace(元空間)目前已使用空間 (位元組)
CCSC:當前壓縮類空間的容量 (位元組)
CCSU:當前壓縮類空間目前已使用空間 (位元組)
YGC:從應用程序啟動到采樣時年輕代中gc次數
YGCT:從應用程序啟動到采樣時年輕代中gc所用時間(s)
FGC:從應用程序啟動到采樣時old代(全gc)gc次數
FGCT:從應用程序啟動到采樣時old代(全gc)gc所用時間(s)
GCT:從應用程序啟動到采樣時gc用的總時間(s)
4.-gccapacity 堆內存統計
[root@hadoop ~]# jstat -gccapacity 3346 #用於查看新生代、老生代及持久代的存儲容量情況 NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0[root@hadoop ~]# jstat -gccapacity -h5 3346 1000 #-h5:每5行顯示一次表頭 1000:每1秒鍾顯示一次,單位為毫秒 NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0 NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0 1280.0 83264.0 1280.0 128.0 128.0 1024.0 15104.0 166592.0 15104.0 15104.0 0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 7 0
NGCMN:年輕代(young)中初始化(最小)的大小(位元組)
NGCMX:年輕代(young)的最大容量 (位元組)
NGC:年輕代(young)中當前的容量 (位元組)
S0C:年輕代中第一個survivor(倖存區)的容量 (位元組)
S1C:年輕代中第二個survivor(倖存區)的容量 (位元組)
EC:年輕代中Eden(伊甸園)的容量 (位元組)
OGCMN:old代中初始化(最小)的大小 (位元組)
OGCMX:old代的最大容量(位元組)
OGC:old代當前新生成的容量 (位元組)
OC:Old代的容量 (位元組)
MCMN:metaspace(元空間)中初始化(最小)的大小 (位元組)
MCMX:metaspace(元空間)的最大容量 (位元組)
MC:metaspace(元空間)當前新生成的容量 (位元組)
CCSMN:最小壓縮類空間大小
CCSMX:最大壓縮類空間大小
CCSC:當前壓縮類空間大小
YGC:從應用程序啟動到采樣時年輕代中gc次數
FGC:從應用程序啟動到采樣時old代(全gc)gc次數
5.-gcmetacapacity 元數據空間統計
[root@hadoop ~]# jstat -gcmetacapacity 3346 #顯示元數據空間的大小MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT0.0 1056768.0 8448.0 0.0 1048576.0 1024.0 8 0 0.000 0.020
MCMN:最小元數據容量
MCMX:最大元數據容量
MC:當前元數據空間大小
CCSMN:最小壓縮類空間大小
CCSMX:最大壓縮類空間大小
CCSC:當前壓縮類空間大小
YGC:從應用程序啟動到采樣時年輕代中gc次數
FGC:從應用程序啟動到采樣時old代(全gc)gc次數
FGCT:從應用程序啟動到采樣時old代(全gc)gc所用時間(s)
GCT:從應用程序啟動到采樣時gc用的總時間(s)
6.-gcnew 新生代垃圾回收統計
[root@hadoop ~]# jstat -gcnew 3346 #用於查看新生代垃圾收集的情況S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT128.0 128.0 67.8 0.0 1 15 64.0 1024.0 362.2 8 0.020
S0C:年輕代中第一個survivor(倖存區)的容量 (位元組)
S1C:年輕代中第二個survivor(倖存區)的容量 (位元組)
S0U:年輕代中第一個survivor(倖存區)目前已使用空間 (位元組)
S1U:年輕代中第二個survivor(倖存區)目前已使用空間 (位元組)
TT:持有次數限制
MTT:最大持有次數限制
DSS:期望的倖存區大小
EC:年輕代中Eden(伊甸園)的容量 (位元組)
EU:年輕代中Eden(伊甸園)目前已使用空間 (位元組)
YGC:從應用程序啟動到采樣時年輕代中gc次數
YGCT:從應用程序啟動到采樣時年輕代中gc所用時間(s)
7.-gcnewcapacity 新生代內存統計
[root@hadoop ~]# jstat -gcnewcapacity 3346 #用於查看新生代存儲容量的情況NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC1280.0 83264.0 1280.0 8320.0 128.0 8320.0 128.0 66624.0 1024.0 8 0
NGCMN:年輕代(young)中初始化(最小)的大小(位元組)
NGCMX:年輕代(young)的最大容量 (位元組)
NGC:年輕代(young)中當前的容量 (位元組)
S0CMX:年輕代中第一個survivor(倖存區)的最大容量 (位元組)
S0C:年輕代中第一個survivor(倖存區)的容量 (位元組)
S1CMX:年輕代中第二個survivor(倖存區)的最大容量 (位元組)
S1C:年輕代中第二個survivor(倖存區)的容量 (位元組)
ECMX:年輕代中Eden(伊甸園)的最大容量 (位元組)
EC:年輕代中Eden(伊甸園)的容量 (位元組)
YGC:從應用程序啟動到采樣時年輕代中gc次數
FGC:從應用程序啟動到采樣時old代(全gc)gc次數
8.-gcold 老年代垃圾回收統計
[root@hadoop ~]# jstat -gcold 3346 #用於查看老年代及持久代垃圾收集的情況MC MU CCSC CCSU OC OU YGC FGC FGCT GCT8448.0 8227.5 1024.0 1003.7 15104.0 2102.2 8 0 0.000 0.020
MC:metaspace(元空間)的容量 (位元組)
MU:metaspace(元空間)目前已使用空間 (位元組)
CCSC:壓縮類空間大小
CCSU:壓縮類空間使用大小
OC:Old代的容量 (位元組)
OU:Old代目前已使用空間 (位元組)
YGC:從應用程序啟動到采樣時年輕代中gc次數
FGC:從應用程序啟動到采樣時old代(全gc)gc次數
FGCT:從應用程序啟動到采樣時old代(全gc)gc所用時間(s)
GCT:從應用程序啟動到采樣時gc用的總時間(s)
9.-gcoldcapacity 老年代內存統計
[root@hadoop ~]# jstat -gcoldcapacity 3346 #用於查看老年代的容量OGCMN OGCMX OGC OC YGC FGC FGCT GCT15104.0 166592.0 15104.0 15104.0 8 0 0.000 0.020
OGCMN:old代中初始化(最小)的大小 (位元組)OGCMX:old代的最大容量(位元組)OGC:old代當前新生成的容量 (位元組)OC:Old代的容量 (位元組)YGC:從應用程序啟動到采樣時年輕代中gc次數FGC:從應用程序啟動到采樣時old代(全gc)gc次數FGCT:從應用程序啟動到采樣時old代(全gc)gc所用時間(s)GCT:從應用程序啟動到采樣時gc用的總時間(s) 在此我向大家推薦一個架構學習交流圈。交流學習指導偽鑫:1253431195(裡面有大量的面試題及答案)裡面會分享一些資深架構師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高並發、高性能、分布式、微服務架構的原理,JVM性能優化、分布式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
10.-gcutil 垃圾回收統計
[root@hadoop ~]# jstat -gcutil 3346 #顯示垃圾收集信息S0 S1 E O M CCS YGC YGCT FGC FGCT GCT52.97 0.00 42.10 13.92 97.39 98.02 8 0.020 0 0.000 0.020
S0:年輕代中第一個survivor(倖存區)已使用的占當前容量百分比
S1:年輕代中第二個survivor(倖存區)已使用的占當前容量百分比
E:年輕代中Eden(伊甸園)已使用的占當前容量百分比
O:old代已使用的占當前容量百分比
M:元數據區已使用的占當前容量百分比
CCS:壓縮類空間已使用的占當前容量百分比
YGC :從應用程序啟動到采樣時年輕代中gc次數
YGCT :從應用程序啟動到采樣時年輕代中gc所用時間(s)
FGC :從應用程序啟動到采樣時old代(全gc)gc次數
FGCT :從應用程序啟動到采樣時old代(全gc)gc所用時間(s)
GCT:從應用程序啟動到采樣時gc用的總時間(s)
11.-gccause
[root@hadoop ~]# jstat -gccause 3346 #顯示垃圾回收的相關信息(通-gcutil),同時顯示最後一次或當前正在發生的垃圾回收的誘因S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC52.97 0.00 46.09 13.92 97.39 98.02 8 0.020 0 0.000 0.020 Allocation Failure No GC
LGCC:最後一次GC原因
GCC:當前GC原因(No GC 為當前沒有執行GC)
12.-printcompilation JVM編譯方法統計
[root@hadoop ~]# jstat -printcompilation 3346 #輸出JIT編譯的方法信息Compiled Size Type Method421 60 1 sun/nio/ch/Util$2 clear
Compiled:編譯任務的數目
Size:方法生成的位元組碼的大小
Type:編譯類型
Method:類名和方法名用來標識編譯的方法。類名使用/做為一個命名空間分隔符。方法名是給定類中的方法。上述格式是由-XX:+PrintComplation選項進行設置的
遠程監控
與jps一樣,jstat也支持遠程監控,同樣也需要開啟安全授權,方法參照jps。
C:\Users\Administrator>jps 192.168.146.1283346 QuorumPeerMain3475 JstatdC:\Users\Administrator>jstat -gcutil [email protected] S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 52.97 0.00 65.15 13.92 97.39 98.02 8 0.020 0 0.000 0.020
❸ GC分析工具
-q:僅輸出VM標識符,不包括classname,jar name,arguments in main method
-m:輸出main method的參數
-l:輸出完全的包名,應用主類名,jar的穗乎完全路空族巧徑名
-v:輸出jvm參數
-V:輸出通過flag文件傳遞到JVM中的斗鍵參數(.hotspotrc文件或-XX:Flags=所指定的文件
l class (類載入器)
l compiler (JIT)
l gc (GC堆狀態)
l gccapacity (各區大小)
l gccause (最近一次GC統計和原因)
l gcnew (新區統計)
l gcnewcapacity (新區大小)
l gcold (老區統計)
l gcoldcapacity (老區大小)
l gcpermcapacity (永久區大小)
l gcutil (GC統計匯總)
l printcompilation (HotSpot編譯統計)
jmap -mp:format=b,file=outfile.bin 1234可以將1234進程的內存heap輸出出來到outfile.bin文件里,再配合MAT(內存分析工具)。
jmap -histo:live>live.log
針對活著的進程做本地的或遠程的線程mp; 美團的CAT有類似功能,可以展示每分鍾堆棧信息
jstack pid > stack.log
分析可能存在內內存泄漏和對象佔用內存情況
https://www.cnblogs.com/hanlinhu/p/10174185.html
gc日誌分析;GC問題分析、gc優化前後詳細指標
https://gceasy.io/diamondgc-report.jsp?oTxnId_value=643c1813-7d09-4a1d-864f-267fa63af00d
http://www.ruanyifeng.com/blog/2017/09/flame-graph.html
❹ 減少長時間的GC停頓
如果您的應用程序的對象創建率很高,因此,垃圾回收率也將非常高。高垃圾收集率也會增弊橘加GC暫停時間。因此,優化應用程序以創建較少數量的對象是減少長GC暫停的有效策略。這可能是比較耗時,但值得100%進行。為了優化應用程序中的對象創建速度,您可以考慮使用Java Profiler(如 JProfiler, YourKit,JVisualVM ...)。這些分析器將報告
小提示:如何計算對象創建率?
當年輕代太小時,對象將被過早地提升為老代。從老年代收集垃圾要比從年輕代收集垃圾花費更多的時間。因此,增加年輕代的大小可以減少長時間的GC暫停。可以通過設置兩個JVM參數中的任何一個來增加年輕代
GC演算法的選擇對GC暫停時間有很大影響。除非您是GC專家或者打算成為一個專家或者團隊中的某人是GC專家,否則您可以調整GC設置以獲得最佳的GC暫停時間。假設您不具備GC專業知識,那麼我建議您使用G1 GC演算法,因為它具有 自動調整功能。在G1 GC中,您可以使用系統屬性「 -XX:MaxGCPauseMillis」設置GC暫停時間目標。例:
根據上面的示例,最大GC暫停時間設置為200毫秒。這是一個軟目標,JVM將盡力實現這一目標。如果您已經在使用G1 GC演算法,並且仍然繼續經歷高暫停時間,請參考本文。
有時由於內存不足(RAM),操作系統可能正在從內存中交換應用程序.Swapping非常昂貴,因為它需要磁碟訪問,這比物理內存訪問要慢得多.交換過程時,GC將花費很長時間才能完成。
下面是從StackOverflow獲得的腳本(感謝作者)-執行該腳本 將顯示所有正在交換的進程。請確保您的進程沒有被交換
如果發現進程正在交換,請執行以下操作之一:
a。向伺服器分配更多RAM
b。減少伺服器上運行的進程數,以便它可以釋放內存(RAM)。
C。減小應用程序的堆大小(我不建議這樣做,因為它可能導致其他副作用).
對於GC日誌中報告的每個GC事件,將列印user,sys和real time。例:
(如果在GC事件中您始終注意到「real time」並不比「user」時間顯著少,則可能表明GC線程不足。考慮增加GC線程數。假設「user」時間為25秒,並且您已將GC線程數配置為5,那麼「real time」應接近5秒(因為25秒/ 5個線程= 5秒)。
警告:添加過多的GC線程將消耗大量CPU,並會佔用應用程序的資源。因此,您需要在增加GC線程數之前進行徹底的測試
如果文件系統的I / O活動繁重(即發生大量讀取和寫入操作),也會導致長時間的GC暫停。這種繁重的文件系統I / O活動可能不是由您的應用程序引起的。可能是由於同一伺服器上正在運行的另一個進程引起的,仍然可能導致您的應用程序長時間處於GC暫停狀態( https://engineering.linkedin.com/blog/2016/02/eliminating-large-jvm-gc-pauses-caused-by-background-io-traffic )
當I / O繁忙時,您會發現「real time」時間要比「user」時間長鍵罩得多。例:
當發生這種模式時,可以使用以下解決方案:
a。如果您的應用程序引起了很高的I / O活動,請對其進行優化。
b。消除導致伺服器上大量I / O活動的進程
C。將您的應用程序移到I / O活動較少的其他伺服器上
Tit-bit: 如何監控io?
您可以在Unix中使用sar(系統活動報告)監視I/O活動。例子:
上面的命令報告每1秒對設備所做的讀/秒和寫/秒。有關「sar」命令的更多細節,請參閱本教程。
1.您自己的應用程序開發人員可能正在顯式調用System.gc()方法。
2.可能是第三方庫,框架,有時甚至是您使用的應用程序伺服器也可能正在調用System.gc()方法。
3.可以通過使用JMX從外部工具(如VisualVM)觸發
4.如果您的應用程序正在使用RMI,則RMI會定期調用System.gc()。可以使用以下系統屬性來配置稿卜鬧此間隔:
-Dsun.rmi.dgc.server.gcInterval = n
-Dsun.rmi.dgc.client.gcInterval = n
評估是否絕對需要顯式調用System.gc()。如果不需要,請刪除它。另一方面,可以通過傳遞JVM參數 '-XX:+ DisableExplicitGC' 來強制禁用System.gc()調用
Tit-bit:如何知道是否顯式調用了System.gc()調用?
大堆大小(-Xmx)也可能導致長時間的GC暫停。如果堆大小很大,那麼堆中將堆積更多的垃圾。當觸發Full GC來清除堆中所有累積的垃圾時,將需要很長時間才能完成。邏輯很簡單:如果您的小罐子里裝滿了垃圾,將可以輕鬆快捷地進行處理。另一方面,如果您有卡車裝滿的垃圾,將需要更多的時間來處理它們。
假設您的JVM堆大小為18GB,然後考慮擁有三個6 GB JVM實例,而不是一個18GB JVM。較小的堆大小具有降低長時間GC暫停的巨大潛力。
注意:上述所有策略均應在經過全面測試和分析後才能投入生產。所有策略可能不適用於您的應用程序。這些策略使用不當會導致負面結果
即使有多個GC線程,有時工作負載也會在GC工作線程之間平均分配。有很多原因導致GC工作負載可能無法平均分配到GC線程中。例如:
a。當前無法並行掃描大型線性數據結構。
b。某些事件僅觸發單個線程收集器(例如,CMS收集中出現「並發模式故障」時)
如果碰巧使用CMS(並發標記和清除演算法),則可以考慮傳遞 -XX:+ CMSScavengeBeforeRemark參數。這樣可以在GC工作線程之間創建更加平衡的工作負載
翻譯自
https://gceasy.io/gc-recommendations/long-pause-solution.jsp
❺ GC調優配置參數
一、JVM調優主要是調整下面兩個指標
1. 停頓時間 :垃圾收集器做垃圾回收中斷應用執行的時間。 -XX:MaxGCPauseMillis
2. 吞吐量 :垃圾收集的時間和總時間的佔比:1/(1+n),吞吐量計算公式為1-1/(1+n), 吞吐量越大,證明性能越好。 -XX:GCTimeRatio=n
二、GC調優步驟
1. 列印GC日誌
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log
Tomcat則直接加在JAVA_OPTS變數里
* 分析日誌得到關鍵性指標
* 分析GC原因,調優JVM參數(工具:gceasy,GCViewer)
2. GC常用參數
堆棧設置
-Xss:每個線程的棧大小
-Xms:初始堆大小,默認物理內存的1/64
-Xmx:最大堆大小,默認物理內存的1/4
-Xmn:新生代大小
-XX:NewSize:設置新生代初始大小
-XX:NewRatio:默認2,表示新生代占老年代的1/2,占整個堆內存的1/3
-XX:SurivivorRatio:默認8,表示一個survivor區佔用1/8的Eden內存,即1/10的新生代內存
-XX:MetaspaceSize:設置元空間大小
-XX:MaxMetaspaceSize:設置元空間最大允許大小,默認不受限制,JVM Metaspace會進行動態擴展
垃圾回收統計信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
收集器設置:
-XX:+UseSerialGC:設置串列收集器
-XX:+UseParallelGC:設置並行收集器
-XX:+UseParallelOldGC:老年代使用並行收集器
-XX:+UseParNewGC:在新生代使用並行收集器
-XX:+UseConcMarkSweepGC:設置CMS並行收集器
-XX:UseG1GC:設置G1收集器
並行收集器設置:
-XX:ParallelGCThreads:設置用於垃圾回收的線程數
-XX:MaxGCPauseMillis:設置並行收集最大暫停時間
-XX:GCTimeRatio:設置垃圾回收時間占程序運行時間的百分比
-XX:YongGenerationSizeIncrement:年輕代GC後擴容的比例,默認是20%
CMS收集器設置
-XX:+UseConcMarkSweepGC:設置CMS並發收集器
-XX:+CMSIncrementalMode:設置為增量模式。適用於單CPU情況
-XX:ParallelGCThreads:設置並發收集器的線程數
-XX:CMSFullGCsBeforeCompanction:設定進行多少次CMS垃圾回收後,進行一次內存壓縮
-XX:+CMSClassUnloadingEnabled:允許對類元數據進行回收
-XX:UseCMSInitiatingOccupancyOnly:表示只在到達閾值的時候,才進行CMS回收
-XX:+CMSIncrementalMode:設置為增量模式,適用於單CPU情況
-XX:ParallelCMSThreads:設定CMS的線程數量
-XX::設置CMS收集器襲啟友在老年代拍槐空間被使用多少後觸發
-XX:+:設置CMS收集器在完成垃圾收集後是否要進行一次內存碎片的整理
G1收集器設置旁茄
-XX:+UseG1GC:使用G1收集器
-XX:ParallelGCThreads:設置並發收集器的線程數
-XX:G1HeapRegionSize:制定分區大小(1MB~32MB,必須是2的冪),默認將整個堆劃分為2048個分區
-XX:GCTimeRatio:吞吐量大小,0-100的整數(默認9),值為n則系統將花費不超過1/(1+n)的時間用於垃圾回收
-XX:MaxGCPauseMillis:目標暫停時間(默認200ms)
-XX:G1NewSizePercent:新生代內存初始空間(默認堆的5%)
-XX:G1MaxNewSizePercent:新生代內存最大空間
-XX:TargetSurvivorRatio:Survivor填充容量(默認50%)
-XX:MaxTenuringThreshold:最大任期閾值(默認15%)
-XX:InitiatingHeapOccupancyPercen:老年代占空間超過整堆比IHOP閾值(默認45%),超過則進行混合收集
-XX:G1HeapWastePercent:堆廢物百分比(默認5%)
❻ GC Log分析
Dalvik虛擬機型衡亂,每一次GC列印內容格式:
含義解析
GC Reason:GC觸發原因
GC_CONCURRENT:當已分配內存達到某一值時,觸發並發GC;
GC_FOR_MALLOC:當嘗試在堆上分配內存不足時觸發的GC;系統必須停止應用程序並回收內存;
GC_HPROF_DUMP_HEAP: 當需要創建HPROF文件來分析堆內存時觸發的GC;
GC_EXPLICIT:當明確的調用GC時,例如調用System.gc()或者通過DDMS工具顯式地告訴系統進行GC操作等;
GC_EXTERNAL_ALLOC: 僅在API級別為10或者更低時(新版本分配內存都在Dalvik堆上)
Amount freed GC:回收的內存大小
Heap stats:堆上的空閑內存百分比 (已用內存)/(堆上總內存)
External memory stats: API級別為10或者更低:(已分配的內存量)/ (即將發生垃圾的極限)
Pause time:這次卜檔GC操作導致應用程序暫停的時間。關於這個暫停的時間,在2.3之前GC操作是不能並發進行的,也就是系統正在進行GC,那麼應用程序就只能阻塞住等待GC結束。而自2.3之後,GC操作改成了並發的方式進行,就是說GC的過程中不會影響到應用程序的正常運行,但是在GC操作的攔爛開始和結束的時候會短暫阻塞一段時間。
Art虛擬機,每一次GC列印內容格式:
I/art:<GC_Reason><Amount_freed>,<LOS_Space_Status>,<Heap_stats>,<Pause_time>,<Total_time>
基本情況和Dalvik沒有什麼差別,GC的Reason更多了,還多了一個LOS_Space_Status.
LOS_Space_Status:Large Object Space,大對象佔用的空間,這部分內存並不是分配在堆上的,但仍屬於應用程序內存空間,主要用來管理 Bitmap 等占內存大的對象,避免因分配大內存導致堆頻繁 GC。