JVM 监控以及内存分析
Java 语言,开发者不能直接控制程序运行内存,对象的创建都是由类加载器一步步解析,执行与生成与内存区域中的;并且 jvm 有自己的垃圾回收器对内存区域管理、回收;但是我们已经可以通过一些工具来在程序运行时查看对应的 jvm 内存使用情况,帮助更好的分析与优化我们的代码。
查看系统里 java 进程信息
1 |
|
jmap -histo
查看类的内存占用
1 |
|
class name 解读
B 代表 byte
C 代表 char
D 代表 double
F 代表 float
I 代表 int
J 代表 long
Z 代表 boolean
前边有[代表数组,[I 就相当于 int[]
对象用[L+类名表示
如果某个类的个数特别多, 就得检查是否内存溢出了。
jmap -heap
1 |
|
MaxHeapFreeRatio: GC 后如果发现空闲堆内存占到整个预估堆内存的 N%(百分比),则收缩堆内存的预估最大值, 预估堆内存是堆大小动态调控的重要选项之一. 堆内存预估最大值一定小于或等于固定最大值(-Xmx 指定的数值). 前者会根据使用情况动态调大或缩小, 以提高 GC 回收的效率
MinHeapFreeRatio: GC 后如果发现空闲堆内存占到整个预估堆内存的 N%(百分比), 则放大堆内存的预估最大值
MaxHeapSize: 即-Xmx, 堆内存大小的上限
InitialHeapSize: 即-Xms, 堆内存大小的初始值
NewSize: 新生代预估堆内存占用的默认值
MaxNewSize: 新生代占整个堆内存的最大值
OldSize: 老年代的默认大小, default size of the tenured generation
NewRatio: 老年代对比新生代的空间大小, 比如 2 代表老年代空间是新生代的两倍大小. The ratio of old generation to young generation.
SurvivorRatio: Eden/Survivor 的值. 这个值的说明, 很多网上转载的都是错的. 8 表示 Survivor:Eden=1:8, 因为 survivor 区有 2 个, 所以 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: 分配给类元数据空间的初始大小(Oracle 逻辑存储上的初始高水位,the initial high-water-mark ). 此值为估计值. MetaspaceSize 设置得过大会延长垃圾回收时间. 垃圾回收过后, 引起下一次垃圾回收的类元数据空间的大小可能会变大
MaxMetaspaceSize: 是分配给类元数据空间的最大值, 超过此值就会触发 Full GC. 此值仅受限于系统内存的大小, JVM 会动态地改变此值
CompressedClassSpaceSize: 类指针压缩空间大小, 默认为 1G
G1HeapRegionSize: G1 区块的大小, 取值为 1M 至 32M. 其取值是要根据最小 Heap 大小划分出 2048 个区块. 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.
指针压缩
- 64 位平台上默认打开 1)使用-XX:+UseCompressedOops 压缩对象指针
“oops”指的是普通对象指针(“ordinary” object pointers)。
Java 堆中对象指针会被压缩成 32 位。
使用堆基地址(如果堆在低 26G 内存中的话,基地址为 0) 2)使用-XX:+UseCompressedClassPointers 选项来压缩类指针
对象中指向类元数据的指针会被压缩成 32 位
类指针压缩空间会有一个基地址 - 元空间和类指针压缩空间的区别 1)类指针压缩空间只包含类的元数据,比如 InstanceKlass, ArrayKlass
仅当打开了 UseCompressedClassPointers 选项才生效
为了提高性能,Java 中的虚方法表也存放到这里
这里到底存放哪些元数据的类型,目前仍在减少 2)元空间包含类的其它比较大的元数据,比如方法,字节码,常量池等。
jstat -gcutil [pid] [internal]
1 |
|
S0: Survivor 0 区的空间使用率 Survivor space 0 utilization as a percentage of the space’s current capacity.
S1: Survivor 1 区的空间使用率 Survivor space 1 utilization as a percentage of the space’s current capacity.
E: Eden 区的空间使用率 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: 元数据的空间使用率 Metaspace utilization as a percentage of the space’s current capacity.
CCS: 类指针压缩空间使用率 Compressed class space utilization as a percentage.
YGC: 新生代 GC 次数 Number of young generation GC events.
YGCT: 新生代 GC 总时长 单位秒 Young generation garbage collection time.
FGC: Full GC 次数 Number of full GC events.
FGCT: Full GC 总时长 单位秒 Full garbage collection time.
GCT: 总共的 GC 时长 单位秒 Total garbage collection time.
查看 JVM 参数及值的命令行工具
-XX:+PrintFlagsInitial 参数
显示所有可设置参数及默认值,可结合-XX:+PrintFlagsInitial 与-XX:+PrintFlagsFinal 对比设置前、设置后的差异,方便知道对那些参数做了调整。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20$ java -XX:+PrintFlagsInitial
[Global flags]
uintx AdaptiveSizeDecrementScaleFactor = 4 {product}
uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product}
uintx AdaptiveSizePausePolicy = 0 {product}
uintx AdaptiveSizePolicyCollectionCostMargin = 50 {product}
uintx AdaptiveSizePolicyInitializingSteps = 20 {product}
uintx AdaptiveSizePolicyOutputInterval = 0 {product}
uintx AdaptiveSizePolicyWeight = 10 {product}
uintx AdaptiveSizeThroughPutPolicy = 0 {product}
uintx AdaptiveTimeWeight = 25 {product}
bool AdjustConcurrency = false {product}
bool AggressiveOpts = false {product}
intx AliasLevel = 3 {C2 product}
bool AlignVector = true {C2 product}
intx AllocateInstancePrefetchLines = 1 {product}
intx AllocatePrefetchDistance = -1 {product}
intx AllocatePrefetchInstr = 0 {product}
intx AllocatePrefetchLines = 3 {product}
intx AllocatePrefetchStepSize = 16 {product}-XX:+PrintFlagsFinal 参数
可以获取到所有可设置参数及值(手动设置之后的值),这个参数只能使用在 Jdk6 update 21 以上版本(包括该版本)。-XX:+PrintFlagsFinal 参数的使用 与上面-XX:+PrintFlagsInitial 参数使用相同1
Java -XX:+PrintFlagsFinal
使用 jinfo 命令 查看或设置某个参数的值,jinfo 命令格式:
1
jinfo [option] <pid>
2017-07-18 更新
jcmd
在 JDK 1.7 之后,新增了一个命令行工具 jcmd。它是一个多功能工具,可以用来导出堆,查看 Java 进程,导出线程信息,执行 GC 等。
列出当前运行的所有虚拟机
1
2
3
4
5
6$ 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参数
-l
表示列出所有 java 虚拟机,针对每一个虚拟机,可以使用 help 命令列出该虚拟机支持的所有命令,如下图所示,以 21167 这个进程为例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28$ 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
help
For more information about a specific command use 'help <command>'.查看虚拟机启动时间 VM.uptime
1
2
3$ jcmd 21167 VM.uptime
21167:
527760.414 s打印线程栈信息 Thread.print
查看系统中类统计信息 GC.class_histogram
导出堆信息 GC.heap_dump(这个命令可以导出当前堆栈信息,功能和
jmap -dump
功能一样)获取系统 Properties 内容 VM.system_properties
获取启动参数 VM.flags
获取所有性能相关数据 PerfCounter.print
总结:jcmd 拥有 jmap 的大部分功能,并且 Oracle 官方也建议使用 jcmd 代替 jmap。