JVM 监控以及内存分析
Java 語言,開發(fā)者不能直接控制程序運(yùn)行內(nèi)存,對象的創(chuàng)建都是由類加載器一步步解析,執(zhí)行與生成與內(nèi)存區(qū)域中的;并且 jvm 有自己的垃圾回收器對內(nèi)存區(qū)域管理、回收;但是我們已經(jīng)可以通過一些工具來在程序運(yùn)行時(shí)查看對應(yīng)的 jvm 內(nèi)存使用情況,幫助更好的分析與優(yōu)化我們的代碼。
查看系統(tǒng)里 java 進(jìn)程信息
// 查看當(dāng)前機(jī)器上所有運(yùn)行的java進(jìn)程名稱與pid(進(jìn)程編號) jps -l // 顯示指定的jvm進(jìn)程所有的屬性設(shè)置和配置參數(shù) jinfo pidjmap -histo
查看類的內(nèi)存占用
$ pid=\`jps | awk '{if ($2 == "Bootstrap") print $1}'` $ jmap -histo $pid >>1.jmapnum #instances #bytes class name ----------------------------------------------1: 16226 862336904 [Ljava.util.HashMap$Node;2: 230727 14940520 [B3: 5105 14082960 [I4: 205826 12756064 [C5: 150472 4815104 java.util.HashMap$Node6: 186884 4485216 java.lang.String7: 277734 4443744 java.lang.Integer8: 108699 4347960 com.jiemo.school.model.impl.SchoolModel9: 128405 4108960 java.util.concurrent.ConcurrentHashMap$Node10: 114 1512448 [Ljava.util.concurrent.ConcurrentHashMap$Node;11: 34496 1511024 [Ljava.lang.Object;12: 25702 1233696 java.nio.HeapByteBuffer13: 34277 1096864 java.util.concurrent.locks.AbstractQueuedSynchronizer$Node14: 7665 856392 java.lang.Class15: 18725 749000 java.util.HashMap$KeyIterator16: 14489 695472 java.nio.HeapCharBuffer17: 28122 674928 java.util.ArrayList18: 25272 642776 [Ljava.lang.String;19: 15380 615200 java.net.DatagramPacketclass name 解讀
B 代表 byte
C 代表 char
D 代表 double
F 代表 float
I 代表 int
J 代表 long
Z 代表 boolean
前邊有 [代表數(shù)組,[I 就相當(dāng)于 int[]
對象用 [L + 類名表示
如果某個(gè)類的個(gè)數(shù)特別多, 就得檢查是否內(nèi)存溢出了。
jmap -heap
$ jmap -heap 22792 Attaching to process ID 19395, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.45-b02using thread-local object allocation. Parallel GC with 8 thread(s)Heap Configuration:MinHeapFreeRatio = 0 # 對應(yīng)jvm啟動參數(shù) -XX:MinHeapFreeRatio 設(shè)置JVM堆最小空閑比率 (默認(rèn)40)MaxHeapFreeRatio = 100 # 對應(yīng)jvm啟動參數(shù) -XX:MaxHeapFreeRatio 設(shè)置JVM堆最大空閑比率 (默認(rèn)70)MaxHeapSize = 8388608000 (8000.0MB) # 對應(yīng)jvm啟動參數(shù) -XX:MaxHeapSize 設(shè)置JVM堆的最大大小NewSize = 44564480 (42.5MB) # 對應(yīng)jvm啟動參數(shù) -XX:NewSize 設(shè)置JVM堆的年輕代的默認(rèn)大小MaxNewSize = 2796027904 (2666.5MB) # 對應(yīng)jvm啟動參數(shù) -XX:MaxNewSize 設(shè)置JVM堆的年輕帶的最大大小OldSize = 89653248 (85.5MB) # 對應(yīng)jvm啟動參數(shù) -XX:OldSize 設(shè)置JVM堆的老年代的大小NewRatio = 2 # 對應(yīng)jvm啟動參數(shù) -XX:NewRatio 老年代與年輕代的大小比率SurvivorRatio = 8 # 對應(yīng)jvm啟動參數(shù) -XX:SurvivorRatio 設(shè)置年輕代中Eden區(qū)與Survivor區(qū)的大小比值MetaspaceSize = 21807104 (20.796875MB) # -XX:MetaspaceSizeCompressedClassSpaceSize = 1073741824 (1024.0MB) # -XX:CompressedClassSpaceSize, 只有當(dāng)-XX:+UseCompressedClassPointers開啟了才有效MaxMetaspaceSize = 536870912 (512.0MB) # -XX:MaxMetaspaceSizeG1HeapRegionSize = 0 (0.0MB)Heap Usage: PS Young Generation Eden Space: # Eden區(qū)內(nèi)存分布 總量 已使用 空閑 使用比率capacity = 404750336 (386.0MB)used = 376643272 (359.1950149536133MB)free = 28107064 (26.80498504638672MB)93.05570335585837% used From Space: # 其中一個(gè)Survivor區(qū)內(nèi)存分布 總量 已使用 空閑 使用比率capacity = 458227712 (437.0MB)used = 383131152 (365.38233947753906MB)free = 75096560 (71.61766052246094MB)83.61151933124464% used To Space: # 另一個(gè)Survivor區(qū)內(nèi)存分布 總量 已使用 空閑 使用比率capacity = 492830720 (470.0MB)used = 0 (0.0MB)free = 492830720 (470.0MB)0.0% used PS Old Generation # 當(dāng)前老年代內(nèi)存分布 總量 已使用 空閑 使用比率capacity = 918552576 (876.0MB)used = 463923192 (442.43163299560547MB)free = 454629384 (433.56836700439453MB)50.50589417758053% used16117 interned Strings occupying 1692808 bytes.MaxHeapFreeRatio: GC 后如果發(fā)現(xiàn)空閑堆內(nèi)存占到整個(gè)預(yù)估堆內(nèi)存的 N%(百分比),則收縮堆內(nèi)存的預(yù)估最大值, 預(yù)估堆內(nèi)存是堆大小動態(tài)調(diào)控的重要選項(xiàng)之一. 堆內(nèi)存預(yù)估最大值一定小于或等于固定最大值 (-Xmx 指定的數(shù)值). 前者會根據(jù)使用情況動態(tài)調(diào)大或縮小, 以提高 GC 回收的效率
MinHeapFreeRatio: GC 后如果發(fā)現(xiàn)空閑堆內(nèi)存占到整個(gè)預(yù)估堆內(nèi)存的 N%(百分比), 則放大堆內(nèi)存的預(yù)估最大值
MaxHeapSize: 即 - Xmx, 堆內(nèi)存大小的上限
InitialHeapSize: 即 - Xms, 堆內(nèi)存大小的初始值
NewSize: 新生代預(yù)估堆內(nèi)存占用的默認(rèn)值
MaxNewSize: 新生代占整個(gè)堆內(nèi)存的最大值
OldSize: 老年代的默認(rèn)大小, default size of the tenured generation
NewRatio: 老年代對比新生代的空間大小, 比如 2 代表老年代空間是新生代的兩倍大小. The ratio of old generation to young generation.
SurvivorRatio: Eden/Survivor 的值. 這個(gè)值的說明, 很多網(wǎng)上轉(zhuǎn)載的都是錯的. 8 表示 Survivor:Eden=1:8, 因?yàn)?survivor 區(qū)有 2 個(gè), 所以 Eden 的占比為 8/10. Ratio of eden/survivor space size. -XX:SurvivorRatio=6 sets the ratio between each survivor space and eden to be 1:6, each survivor space will be one eighth of the young generation.
MetaspaceSize: 分配給類元數(shù)據(jù)空間的初始大小 (Oracle 邏輯存儲上的初始高水位,the initial high-water-mark). 此值為估計(jì)值. MetaspaceSize 設(shè)置得過大會延長垃圾回收時(shí)間. 垃圾回收過后, 引起下一次垃圾回收的類元數(shù)據(jù)空間的大小可能會變大
MaxMetaspaceSize: 是分配給類元數(shù)據(jù)空間的最大值, 超過此值就會觸發(fā) Full GC. 此值僅受限于系統(tǒng)內(nèi)存的大小, JVM 會動態(tài)地改變此值
CompressedClassSpaceSize: 類指針壓縮空間大小, 默認(rèn)為 1G
G1HeapRegionSize: G1 區(qū)塊的大小, 取值為 1M 至 32M. 其取值是要根據(jù)最小 Heap 大小劃分出 2048 個(gè)區(qū)塊. With G1 the Java heap is subdivided into uniformly sized regions. This sets the size of the individual sub-divisions. The default value of this parameter is determined ergonomically based upon heap size. The minimum value is 1Mb and the maximum value is 32Mb. Sets the size of a G1 region. The value will be a power of two and can range from 1MB to 32MB. The goal is to have around 2048 regions based on the minimum Java heap size.
指針壓縮
1) 使用 - XX:+UseCompressedOops 壓縮對象指針
“oops” 指的是普通對象指針 (“ordinary” object pointers)。
Java 堆中對象指針會被壓縮成 32 位。
使用堆基地址(如果堆在低 26G 內(nèi)存中的話,基地址為 0)
2) 使用 - XX:+UseCompressedClassPointers 選項(xiàng)來壓縮類指針
對象中指向類元數(shù)據(jù)的指針會被壓縮成 32 位
類指針壓縮空間會有一個(gè)基地址
1) 類指針壓縮空間只包含類的元數(shù)據(jù),比如 InstanceKlass, ArrayKlass
僅當(dāng)打開了 UseCompressedClassPointers 選項(xiàng)才生效
為了提高性能,Java 中的虛方法表也存放到這里
這里到底存放哪些元數(shù)據(jù)的類型,目前仍在減少
2) 元空間包含類的其它比較大的元數(shù)據(jù),比如方法,字節(jié)碼,常量池等。
jstat -gcutil [pid] [internal]
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 83.61 0.00 93.25 50.51 97.92 93.98 32 45.703 10 16.852 62.555S0: Survivor 0 區(qū)的空間使用率 Survivor space 0 utilization as a percentage of the space’s current capacity.
S1: Survivor 1 區(qū)的空間使用率 Survivor space 1 utilization as a percentage of the space’s current capacity.
E: Eden 區(qū)的空間使用率 Eden space utilization as a percentage of the space’s current capacity.
O: 老年代的空間使用率 Old space utilization as a percentage of the space’s current capacity.
M: 元數(shù)據(jù)的空間使用率 Metaspace utilization as a percentage of the space’s current capacity.
CCS: 類指針壓縮空間使用率 Compressed class space utilization as a percentage.
YGC: 新生代 GC 次數(shù) Number of young generation GC events.
YGCT: 新生代 GC 總時(shí)長 單位秒 Young generation garbage collection time.
FGC: Full GC 次數(shù) Number of full GC events.
FGCT: Full GC 總時(shí)長 單位秒 Full garbage collection time.
GCT: 總共的 GC 時(shí)長 單位秒 Total garbage collection time.
查看 JVM 參數(shù)及值的命令行工具
-XX:+PrintFlagsInitial 參數(shù)
顯示所有可設(shè)置參數(shù)及默認(rèn)值,可結(jié)合 - XX:+PrintFlagsInitial 與 - XX:+PrintFlagsFinal 對比設(shè)置前、設(shè)置后的差異,方便知道對那些參數(shù)做了調(diào)整。
?
-XX:+PrintFlagsFinal 參數(shù)
可以獲取到所有可設(shè)置參數(shù)及值 (手動設(shè)置之后的值),這個(gè)參數(shù)只能使用在 Jdk6 update 21 以上版本 (包括該版本)。-XX:+PrintFlagsFinal 參數(shù)的使用 與上面 - XX:+PrintFlagsInitial 參數(shù)使用相同
使用 jinfo 命令 查看或設(shè)置某個(gè)參數(shù)的值,jinfo 命令格式:
?
jcmd
在 JDK 1.7 之后,新增了一個(gè)命令行工具 jcmd。它是一個(gè)多功能工具,可以用來導(dǎo)出堆,查看 Java 進(jìn)程,導(dǎo)出線程信息,執(zhí)行 GC 等。
-
列出當(dāng)前運(yùn)行的所有虛擬機(jī)
[root@apple ~]# jcmd -l 30356 com.aliyun.tianji.cloudmonitor.Application 8757 org.jruby.Main /opt/logstash/lib/bootstrap/environment.rb logstash/runner.rb -f /etc/logstash/conf.d/event-operate-post-shipper.yaml 8713 org.jruby.Main /opt/logstash/lib/bootstrap/environment.rb logstash/runner.rb -f /etc/logstash/conf.d/statistics-shipper.yaml 11615 sun.tools.jcmd.JCmd -l 21167 org.apache.catalina.startup.Bootstrap start [root@apple ~]# ?參數(shù)-l表示列出所有 java 虛擬機(jī),針對每一個(gè)虛擬機(jī),可以使用 help 命令列出該虛擬機(jī)支持的所有命令,如下圖所示,以 21167 這個(gè)進(jìn)程為例:
[root@apple ~]# jcmd 21167 help 21167: The following commands are available: JFR.stop JFR.start JFR.dump JFR.check VM.native_memory VM.check_commercial_features VM.unlock_commercial_features ManagementAgent.stop ManagementAgent.start_local ManagementAgent.start GC.rotate_log Thread.print GC.class_stats GC.class_histogram GC.heap_dump GC.run_finalization GC.run VM.uptime VM.flags VM.system_properties VM.command_line VM.version helpFor more information about a specific command use 'help <command>'.查看虛擬機(jī)啟動時(shí)間 VM.uptime
- [root@apple ~]# jcmd 21167 VM.uptime
21167:
527760.414 s
?
-
打印線程棧信息 Thread.print
- 查看系統(tǒng)中類統(tǒng)計(jì)信息 GC.class_histogram
- 導(dǎo)出堆信息 GC.heap_dump(這個(gè)命令可以導(dǎo)出當(dāng)前堆棧信息,功能和jmap -dump功能一樣)
- 獲取系統(tǒng) Properties 內(nèi)容 VM.system_properties
- 獲取啟動參數(shù) VM.flags
- 獲取所有性能相關(guān)數(shù)據(jù) PerfCounter.print
總結(jié):jcmd 擁有 jmap 的大部分功能,并且 Oracle 官方也建議使用 jcmd 代替 jmap。
- 本文作者:?Yibo
- 本文鏈接:?https://windmt.com/2016/08/01/jvm-monitoring/
- 版權(quán)聲明:?本博客所有文章除特別聲明外,均采用?CC BY-NC-SA 4.0?許可協(xié)議。轉(zhuǎn)載請注明出處!
總結(jié)
以上是生活随笔為你收集整理的JVM 监控以及内存分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring 原理初探——IoC、AOP
- 下一篇: 极客时间专栏