非常不容易呀,本章完结后,jvm的主要专题基本算完整了,就先暂时告一段落了,感谢大家的支持。由于笔者水平有限,也欢迎大家指正哈。
本章主要是描述下JVM调优过程中主要用的一些工具和命令,可当做工具手册来使用。
一、jvm常用命令
1.1、常用性能查看命令
top:系统情况;
vmstat:cpu和内存
iostat:IO情况
jps -m -l:输出系统下所有的java进程; -v显示jvm参数
jstat:查看jvm运行时信息,jstat -xx pid,xx为要显示的信息
jinfo:查看和修改运行时的JVM进程的jvm参数
jmap:jmap -histo pid >c:\a.txt 导出堆信息, jmap -dump:format=b, file=c:\dd.hprop导出堆快照
jmap -permstat pid:查看classloader信息
jstack:查看栈信息
1.2、性能调优先步骤
#优先查看:
系统每秒请求数、每个请求创建多少对象,占用多少内存。
Young GC 触发频率、对象进入老年代的速率。
老年代占用内存、Full GC 触发频率、Full GC 触发的原因、时长 Full GC 的原因。
uptime 一般数值在0.7正常
top
top -Hp pid
printf "%x\n” pid
jstack pid | grep 0xpid
PID:进程的ID
USER:进程所有者
PR:进程的优先级别,越小越优先被执行
NInice:值
VIRT:进程占用的虚拟内存
RES:进程占用的物理内存
SHR:进程使用的共享内存
S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数
%CPU:进程占用CPU的使用率
%MEM:进程使用的物理内存和总内存的百分比
TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
COMMAND:进程启动命令名称
$ pmap -d 14596
扩展格式和设备格式域:
Address: start address of map 映像起始地址
Kbytes: size of map in kilobytes 映像大小
RSS: resident set size in kilobytes 驻留集大小
Dirty: dirty pages (both shared and private) in kilobytes 脏页大小
Mode: permissions on map 映像权限: r=read, w=write, x=execute, s=shared, p=private (copy on write)
Mapping: file backing the map , or '[ anon ]' for allocated memory, or '[ stack ]' for the program stack. 映像支持文件,[anon]为已分配内存 [stack]为程序堆栈
mapped: 8348488K writeable/private: 2929624K shared: 4580K
最后一行的值
mapped 表示该进程映射的虚拟地址空间大小,也就是该进程预先分配的虚拟内存大小,即ps出的vsz
writeable/private 表示进程所占用的私有地址空间大小,也就是该进程实际使用的内存大小
shared 表示进程和其他进程共享的内存大小
循环显示最后一行,试试监控进程内存占用情况: # while true; do pmap -d 5002 | tail -1; sleep 3; done
jps -v
jmap pid
jinfo -flag MaxPermSize 2788
jmap -histo pid
ps -aux | grep pid
cat /proc/pid/status
1.3、jstat命令
类加载统计
类加载统计:
jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]
jstat -class 2060
编译统计
编译统计
jstat -compiler 2060
JVM编译方法统计
jstat -printcompilation pid
Compiled:最近编译方法的数量
Size:最近编译方法的字节码数量
Type:最近编译方法的编译类型。
Method:方法名标识。
垃圾回收统计
垃圾回收统计
jstat -gc pid
S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
堆内存统计
jstat -gccapacity pid
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0C:第一个幸存区大小
S1C:第二个幸存区的大小
EC:伊甸园区的大小
OGCMN:老年代最小容量
OGCMX:老年代最大容量
OGC:当前老年代大小
OC:当前老年代大小
MCMN:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:年轻代gc次数
FGC:老年代GC次数
新生代垃圾回收统计
jstat -gcnew pid
S0C:第一个幸存区大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
TT:对象在新生代存活的次数
MTT:对象在新生代存活的最大次数
DSS:期望的幸存区大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
新生代内存统计
jstat -gcnewcapacity pid
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0CMX:最大幸存1区大小
S0C:当前幸存1区大小
S1CMX:最大幸存2区大小
S1C:当前幸存2区大小
ECMX:最大伊甸园区大小
EC:当前伊甸园区大小
YGC:年轻代垃圾回收次数
FGC:老年代回收次数
老年代垃圾回收统计
jstat -gcold pid
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
OC:老年代大小
OU:老年代使用大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
元数据空间统计
jstat -gcmetacapacity pid
MCMN:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
总结垃圾回收统计
jstat -gcutil pid
S0:幸存1区当前使用比例
S1:幸存2区当前使用比例
E:伊甸园区使用比例
O:老年代使用比例
M:元数据区使用比例
CCS:压缩使用比例
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
1.4、vmstat命令
vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令,一个是Linux/Unix都支持,二是相比top,我可以看到整个机器的CPU,内存,IO的使用情况,而不是单单看到各个进程的CPU使用率和内存使用率(使用场景不一样)。一般vmstat工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数,如:
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
1 0 0 3499840 315836 3819660 0 0 0 1 2 0 0 0 100 0
- r:表示运行队列(就是说多少个进程真的分配到CPU),我测试的服务器目前CPU比较空闲,没什么程序在跑,当这个值超过了CPU数目,就会出现CPU瓶颈了。这个也和top的负载有关系,一般负载超过了3就比较高,超过了5就高,超过了10就不正常了,服务器的状态很危险。top的负载类似每秒的运行队列。如果运行队列过大,表示你的CPU很繁忙,一般会造成CPU使用率很高。
- b:表示阻塞的进程,这个不多说,进程阻塞,大家懂的。
- swpd:虚拟内存已使用的大小,如果大于0,表示你的机器物理内存不足了,如果不是程序内存泄露的原因,那么你该升级内存了或者把耗内存的任务迁移到其他机器
- free:空闲的物理内存的大小,我的机器内存总共8G,剩余3415M。
- buff:Linux/Unix系统是用来存储,目录里面有什么内容,权限等的缓存,我本机大概占用300多M
- cache:cache直接用来记忆我们打开的文件,给文件做缓冲,我本机大概占用300多M(这里是Linux/Unix的聪明之处,把空闲的物理内存的一部分拿来做文件和目录的缓存,是为了提高 程序执行的性能,当程序使用内存时,buffer/cached会很快地被使用。)
- si:每秒从磁盘读入虚拟内存的大小,如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉。我的机器内存充裕,一切正常。
- so:每秒虚拟内存写入磁盘的大小,如果这个值大于0,同上。
- bi:块设备每秒接收的块数量,这里的块设备是指系统上所有的磁盘和其他块设备,默认块大小是1024byte,我本机上没什么IO操作,所以一直是0,但是我曾在处理拷贝大量数据(2-3T)的机器上看过可以达到140000/s,磁盘写入速度差不多140M每秒
- bo:块设备每秒发送的块数量,例如我们读取文件,bo就要大于0。bi和bo一般都要接近0,不然就是IO过于频繁,需要调整
- in:每秒CPU的中断次数,包括时间中断
- cs:每秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好,太大了,要考虑调低线程或者进程的数目,例如在apache和nginx这种web服务器中,我们一般做性能测试时会进行几千并发甚至几万并发的测试,选择web服务器的进程可以由进程或者线程的峰值一直下调,压测,直到cs到一个比较小的值,这个进程和线程数就是比较合适的值了。系统调用也是,每次调用系统函数,我们的代码就会进入内核空间,导致上下文切换,这个是很耗资源,也要尽量避免频繁调用系统函数。上下文切换次数过多表示你的CPU大部分浪费在上下文切换,导致CPU干正经事的时间少了,CPU没有充分利用,是不可取的。
- us:用户CPU时间,我曾经在一个做加密解密很频繁的服务器上,可以看到us接近100,r运行队列达到80(机器在做压力测试,性能表现不佳)。
- sy:系统CPU时间,如果太高,表示系统调用时间长,例如是IO操作频繁。
- id:空闲 CPU时间,一般来说,id + us + sy = 100,一般我认为id是空闲CPU使用率,us是用户CPU使用率,sy是系统CPU使用率。
- wt:等待IO CPU时间。
1.5、jcmd命令
jcmd pid help ,以下是这些可选命令
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
1.6、netstat命令
netstat用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。
语法:netstat [-acCeFghilMnNoprstuvVwx][-A<网络类型>][--ip]
-a或–all 显示所有连线中的Socket。
-A<网络类型>或–<网络类型> 列出该网络类型连线中的相关地址。
-c或–continuous 持续列出网络状态。
-C或–cache 显示路由器配置的快取信息。
-e或–extend 显示网络其他相关信息。
-F或–fib 显示FIB。
-g或–groups 显示多重广播功能群组组员名单。
-h或–help 在线帮助。
-i或–interfaces 显示网络界面信息表单。
-l或–listening 显示监控中的服务器的Socket。
-M或–masquerade 显示伪装的网络连线。
-n或–numeric 直接使用IP地址,而不通过域名服务器。
-N或–netlink或–symbolic 显示网络硬件外围设备的符号连接名称。
-o或–timers 显示计时器。
-p或–programs 显示正在使用Socket的程序识别码和程序名称。
-r或–route 显示Routing Table。
-s或–statistice 显示网络工作信息统计表。
-t或–tcp 显示TCP传输协议的连线状况。
-u或–udp 显示UDP传输协议的连线状况。
-v或–verbose 显示指令执行过程。
-V或–version 显示版本信息。
-w或–raw 显示RAW传输协议的连线状况。
-x或–unix 此参数的效果和指定”-A unix”参数相同。
–ip或–inet 此参数的效果和指定”-A inet”参数相同
二、jvm常用工具
2.1、常用JVM配置
动态打印GC信息:-verbose:gc和-XX:+PrintGC,这两个参数设置后,下面的参数才会生效
-XX:+TraceClassLoading:跟踪类加载情况
-XX:+TraceClassUnLoading:跟踪类卸载情况
-Xnoclassgc:禁止gc时卸载类
-XX:+UseCompressedOops:打开指标压缩,减少64位机器上指标的大小,减少内存占用
-XX:-FailOverToOldVerifier:关闭老校验器功能
-Xverify:none:禁用类验证功能
2.2、OQL
如果想自行开发,需要引入org-netbeans-lib-*的相关jar包。
heap堆操作
###heap操作
1、select heap.findClass("java.util.Vector") 查询特定的类
2、select heap.findClass("java.util.Vector").superclasses() 查询所有父类,可选的方法还有:
isSubclassof():是否是指定类的子类
isSuperclassof():是否是指定类的父类
subclasses():返回所有子类
3、select filter(heap.classes(), "/java.io./") 查询特定包下的所有类的集合
4、select heap.objects("java.io.File", true) 查询当前堆中所有File的实例
5、select heap.livepaths(s) from java.lang.String s where s.toString() == '56' //查询值为56的字符串的引用链
对象操作
##classof()函数
//属性有:name, superclass, statics, fields
//方法有:isSubclassOf(), isSuperclassOf(), subclasses(), superclasses()
select classof(v) from instanceof java.util.Vector v
## objectid()函数,返回指定对象的ID
select objectid(v) from instanceof java.util.Vector v
##referrers()函数,返回引用给定对象的对像集合
select referrers(s) from java.lang.String s where s.toString() == '56'
##referees()函数,返回引用给定对象的直接引用对象集合
##sizeof():不包含引用对象
##rsixeof():包含引用对象
select {size:sizeof(o), rsize:rsizeof(o)} from java.util.Vector o
String相关
(1)查询长度大于100的字符串 select s from java.lang.String s where s.count > 100
(2)查询长度大于256的数组 select a from [I a where a.length > 256
(3)显示匹配某一正则表达式的字符串 select a.value.toString() from java.lang.String s where /java/(s.value.toString())
(4)显示所有文件对象的文件路径 select file.path.value.toString() from java.io.File file
(5)显示所有ClassLoader的类名 select classof(cl).name from instanceof java.lang.ClassLoader cl
(6)通过引用查询对象 select o from instanceof 0xd404d404 o
(7)通过top consumers查找大对象,可以按照class、classloader和package进行group by
统计函数
##max()
##min()
##top()
##sort()
##length()
select count(heap.classes(), "/java.io./")
2.3、java工具
JMeter工具-压测工具
cd /Users/liudong/projectDev/jmeter-5.4.3/bin
sh jmeter
*jvisualvm:jvm自带的性能查看工具,也可连接远程机器,这个工具是可以右键点击的
通过jvisualvm启动
需要远程主机启动时配置
JAVA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false - Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=11.212.121.12 : 这行不知道要不要写
-Dcom.sun.management.jmxremote :允许使用JMX远程管理
-Dcom.sun.management.jmxremote.port=9008 :JMX远程连接端口
-Dcom.sun.management.jmxremote.authenticate=false :不进行身份认证,任何用户都可以连接
-Dcom.sun.management.jmxremote.ssl=false :不使用ssl
jconsole:jvm自带的性能查看工具,也可连接远程机器
jconsole: 直接打命令启动, 可查看:内存,线程,类加载情况,VM参数,MBean信息
MISSION CONTROL: 直接打命令启动,以上命令和jcm命令一样的功能
HSDB:java自带的运行时分析工具,也可远程debug java -cp sa-jdi.jar sun.jvm.hotspot.HSDB
jhat:java自带的dump堆分析工具
导出dump文件
1、jmap -dump:live,file=a.log pid //pid可从jconsole连接窗口上取或是用jcmd命令取
2、从jconsole软件导出:选中面板中的”MBeans”,并点开左边栏中的依次打开com.sum.management/HotSpotDiagnostic/Operations/dumpHeap。
Operation invocation下p0参数填上提取出heap dump后的存储路径,如:/Users/liudong/aa.hprof P1参数写true
分析
jhat -J-Xmx512M a1.log
查看
访问 http://localhost:7000/
然后要拉到页面最下面:
Show all members of the rootset 从根集能引用到的对象
Show instance counts for all classes (excluding platform) 显示平台包括的所有类的实例数量
Show instance counts for all classes (including platform) 显示出堆中所包含的所有的类
Show heap histogram 堆实例的分布表--【这个最常用】
Execute Object Query Language (OQL) query 执行对象查询语句
Show finalizer summary 显示GC回收情况
*MAT:dump堆分析工具
下载地址 https://www.eclipse.org/mat/downloads.php
然后修改软件包中 info.list文件中的<string>-vm</string><string>/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/java</string>