JVM性能监控与调优
2024-07-09 13:59:31 0 举报
AI智能生成
登录查看完整内容
JVM性能监控与调优
作者其他创作
大纲/内容
youngGC次数
youngGC时间
fullGC次数
fullGC时间
jstat -gc pid 命令可以计算一些关键数据
堆内存大小
年轻代大小
Eden和Survivor的比例
老年代的大小
对象的阈值
需要考虑的jvm参数设置
JVM运行情况预估
命令 jstat -gc pid 1000 10,通过观察eden区的使用来估算每秒eden大概新增多少对象
高峰期
日常运行期
不同的时间分别估算不同情况下对象增长速率
关注年轻代对象增长的速率
Young GC的平均耗时 = YGCT/YGC
关注Young GC的触发频率和每次耗时
Full GC的平均耗时 = FGCT/FGC
关注Full GC的触发频率和每次耗时
1.尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留存在年轻代里
尽量别让对象进入老年代
尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响
总结
JVM调优思路
元空间不够导致的多余full gc
老年代空间分配担保机制
显示调用System.gc()造成多余的full gc
full gc比minor gc还多的原因
可以执行命令 jstat -gc pid 1000 10 (每隔1秒执行1次命令,共执行10次),通过观察EU(eden区的使用)来估算每秒eden大概新增多少对象,如果系统负载不高,可以把频率1秒换成1分钟,甚至10分钟来观察整体情况。注意,一般系统可能有高峰期和日常期,所以需要在不同的时间分别估算不同情况下对象增长速率。
年轻代对象增长的速率
知道年轻代对象增长速率我们就能推根据eden区的大小推算出Young GC大概多久触发一次,Young GC的平均耗时可以通过 YGCT/YGC 公式算出,根据结果我们大概就能知道系统大概多久会因为Young GC的执行而卡顿多久
Young GC的触发频率和每次耗时
这个因为之前已经大概知道Young GC的频率,假设是每5分钟一次,那么可以执行命令 jstat -gc pid 300000 10 ,观察每次结果eden,survivor和老年代使用的变化情况,在每次gc后eden区使用一般会大幅减少,survivor和老年代都有可能增长,这些增长的对象就是每次Young GC后存活的对象,同时还可以看出每次Young GC后进去老年代大概多少对象,从而可以推算出老年代对象增长速率
每次Young GC后有多少对象存活和进入老年代
知道了老年代对象的增长速率就可以推算出Full GC的触发频率了,Full GC的每次耗时可以用公式 FGCT/FGC 计算得出。
Full GC的触发频率和每次耗时
优化思路: 尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留存在年轻代里。尽量别让对象进入老年代。尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响。
图灵优化案例
生产环境应该给服务器分配多少内存合适?
如何对垃圾回收器的性能进行调优?
生产环境应该给应用分配多少线程合适?
不加log,如何确定请求是否执行了某一行代码?
子主题
1、生产环境中的问题
防止出现OOM
解决OOM
减少Full GC出现的频率
2、为什么要调优
上线前
项目运行阶段
线上出现OOM
3、不同阶段的考虑
背景说明
运行日志
异常堆栈
GC日志
线程快照
堆转储快照
1、监控的依据
合理地编写代码
充分并合理的使用硬件资源
合理地进行JVM调优
2、调优的大方向
调优概述
GC频繁
cpu load过高
OOM
内存泄露
死锁
程序响应时间较长
第1步(发现问题):性能监控
打印GC日志,通过GCviewer或者 http://gceasy.io来分析异常信息
灵活运用命令行工具、jstack、jmap、jinfo等
dump出堆文件,使用内存分析工具分析文件
使用阿里Arthas、jconsole、JVisualVM来实时查看JVM状态
jstack查看堆栈信息
第2步(排查问题):性能分析
适当增加内存,根据业务背景选择垃圾回收器
优化代码,控制内存使用
增加机器,分散节点压力
合理设置线程池线程数量
使用中间件提高程序效率,比如缓存、消息队列等
第3步(解决问题):性能调优
性能优化的步骤
在垃圾回收器环节中,执行垃圾收集时,程序的工作线程被暂停的时间(STW)
停顿时间(或响应时间)
对单位时间内完成的工作量(请求)的量度
在GC中:运行用户代码的事件占总运行时间的比例(总运行时间:程序的运行时间+内存回收的时间)吞吐量为1-1/(1+n),其中-XX::GCTimeRatio=n
吞吐量
同一时刻,对服务器有实际交互的请求数
并发数
Java堆区所占的内存大小
内存占用
以高速公路通行状况为例
相互间的关系
性能评价/测试指标
关键问题思考
概述
此命令可以用来查看内存信息,实例个数以及占用内存大小
jmap -histo 14660 #查看历史生成的实例
jmap -histo:live 14660 #查看当前存活的实例,执行过程中可能会触发一次full gc
num:序号题
instances:实例数量
bytes:占用空间大小
class name:类名称,[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]
展示内容
jmap -histo 线程号
jmap -heap 14460
查看堆信息
jmap -heap
查看堆内存dump
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./ (路径)
也可以设置内存溢出自动导出dump文件(内存很大的时候,可能会导不出来)
jvisualvm命令工具分析dump
jmap -dump
Jmap
查看死锁信息
还可以用jvisualvm自动检测死锁
pid是你的java进程号
通过top -p <pid> ,显示你的java进程的内存情况
H必须大写
按H,获取每个线程的内存情况
进程号可以直接使用,而线程号需要转成16进制
找到内存和cpu占用最高的线程tid
这个命令的意思是通过jstack查看此进程下的线程命令,通过通道进行线程间的通信。
执行 jstack 19663|grep -A 10 4cd0
使用此命令查找占用CPU的线程
Jstack
查看正在运行的Java应用程序的扩展参数
查看jvm的参数
jinfo -flag 进程号
查看java系统参数
jinfo -props 进程号
Jinfo
可以查看堆内存各部分的使用量,以及加载类的数量
例子:jstat -gc pid 1000 10 (每隔1秒执行1次命令,共执行10次)
jstat [-命令选项] [vmid] [间隔时间(毫秒)] [查询次数]
S0C:第一个幸存区的大小,单位KBS1C:第二个幸存区的大小S0U:第一个幸存区的使用大小S1U:第二个幸存区的使用大小EC:伊甸园区的大小EU:伊甸园区的使用大小OC:老年代大小OU:老年代使用大小MC:方法区大小(元空间)MU:方法区使用大小CCSC:压缩类空间大小CCSU:压缩类空间使用大小YGC:年轻代垃圾回收次数YGCT:年轻代垃圾回收消耗时间,单位sFGC:老年代垃圾回收次数 FGCT:老年代垃圾回收消耗时间,单位sGCT:垃圾回收消耗总时间,单位s
查看程序内存使用及GC压力整体情况
jstat -gc pid
堆内存统计
jastat -gccapacity pid
常用命令
Jstat
常用调优命令
源码
简单命令行工具
jps(Java Process Status):显示指定系统内所有的HotSpot虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程(对于本地虚拟机进程来说,进程的本地虚拟机ID与操作系统的进程ID是一致的,是唯一的)
-q :仅仅显示LVMID (local virtual machine id),即本地虚拟机唯一id。不显示主类的名称等
-l :输出应用程序主类的全类名 或 如果进程执行的是jar包,则输出jar完整路径
-m :输出虚拟机进程启动时传递给主类main()的参数
-v :列出虚拟机进程启动时的JVM参数。 比如:-Xms20m -Xmx50m是启动程序指定的jvm参数。
说明:以上参数可以综合使用。补充:如果某Java进程关闭了默认开启的UsePerfData参数(即使用参数font color=\"#a23c73\
语法:命令 > 文件名称例如:jps -l > a.txt
如何将信息输出到同级文件中
options 参数
RMI注册表中注册的主机名。如果想要远程监控主机上的 java 程序,需要安装 jstatd。对于具有更严格的安全实践的网络场所而言,可能使用一个自定义的策略文件来显示对特定的可信主机或网络的访问,尽管这种技术容易受到IP地址欺诈攻击。如果安全问题无法使用一个定制的策略文件来处理,那么最安全的操作是不运行jstatd服务器,而是在本地使用jstat和jps工具。
hostid参数
语法
jps: 查询正在运行的Java进程
jstat(JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的font color=\"#e74f4c\
Timestamp代表程序至今的运行时间,单位为秒;Loaded代表加载的类的数目;Bytes代表加载的类的总字节数;Unloaded代表卸载的类的数目;Time代表类装载所消耗的时间;
-class
S0C是第一个幸存者区的大小(字节)
S1C是第二个幸存者区的大小(字节)
S0U是第一个幸存者区已使用的大小(字节)
S1U是第二个幸存者区已使用的大小(字节)
EC是Eden空间的大小(字节)
EU是Eden空间已使用大小(字节)
新生代相关
OC是老年代的大小(字节)
OU是老年代已使用的大小(字节)
老年代相关
MC是方法区的大小
MU是方法区已使用的大小
CCSC是压缩类空间的大小
CCSU是压缩类空间已使用的大小
方法区(元空间)相关
YGC是从应用程序启动到采样时young
YGCT是指从应用程序启动到采样时young gc消耗时间(秒)
FGC是从应用程序启动到采样时full gc的次数
FGCT是从应用程序启动到采样时的full gc的消耗时间(秒)
GCT是从应用程序启动到采样时gc的总时间
其他
S0C代表幸存者0区的总容量,S1C代表幸存者1区的总容量,S0U代表幸存者0区使用的容量,S1U代表幸存者1区使用的容量,EC代表伊甸园区的总容量,EU代表伊甸园区使用的总容量,OC代表老年代的总容量,OU代表老年代已经使用的容量,MC代表方法区的总容量,MU代表方法区的总容量,CCSC代表压缩类的总容量,CCSU代表压缩类使用的容量,YGC代表年轻代垃圾回收的次数,YGCT年轻代进行垃圾回收需要的时间,FGC代表代表Full GC的次数,FGCT代表Full GC的时间,GCT代表垃圾回收的总时间
-gc
NGCMN:新生代最小容量NGCMX:新生代最大容量NGC:当前新生代容量S0C:第一个幸存区大小S1C:第二个幸存区的大小EC:伊甸园区的大小OGCMN:老年代最小容量OGCMX:老年代最大容量OGC:当前老年代大小OC:当前老年代大小MCMN:最小元数据容量MCMX:最大元数据容量MC:当前元数据空间大小CCSMN:最小压缩类空间大小CCSMX:最大压缩类空间大小CCSC:当前压缩类空间大小YGC:年轻代gc次数FGC:老年代GC次数
-gccapacity : 【堆内存统计】
S0:幸存1区当前使用比例S1:幸存2区当前使用比例E:伊甸园区使用比例O:老年代使用比例M:元数据区使用比例CCS:压缩使用比例YGC:年轻代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收消耗时间GCT:垃圾回收消耗总时间
-gcutil
S0代表幸存者0区,S1代表幸存者1区,E代表伊甸园区,O代表老年代,M代表方法区,CCS代表压缩类,以上这些值都是占比情况,YGC代表年轻代垃圾回收的次数,YGCT年轻代进行垃圾回收需要的时间,FGC代表代表Full GC的次数,FGCT代表Full GC的时间,GCT代表垃圾回收的总时间,LGCC和GCC代表垃圾回收的原因
-gccause 【垃圾回收情况】
S0C:第一个幸存区的大小S1C:第二个幸存区的大小S0U:第一个幸存区的使用大小S1U:第二个幸存区的使用大小TT:对象在新生代存活的次数MTT:对象在新生代存活的最大次数DSS:期望的幸存区大小EC:伊甸园区的大小EU:伊甸园区的使用大小YGC:年轻代垃圾回收次数YGCT:年轻代垃圾回收消耗时间
-gcnew 【新生代垃圾回收】
NGCMN:新生代最小容量NGCMX:新生代最大容量NGC:当前新生代容量S0CMX:最大幸存1区大小S0C:当前幸存1区大小S1CMX:最大幸存2区大小S1C:当前幸存2区大小ECMX:最大伊甸园区大小EC:当前伊甸园区大小YGC:年轻代垃圾回收次数FGC:老年代回收次数
-gcnewcapacity 【新生代空间统计】
MC:方法区大小MU:方法区使用大小CCSC:压缩类空间大小CCSU:压缩类空间使用大小OC:老年代大小OU:老年代使用大小YGC:年轻代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收消耗时间GCT:垃圾回收消耗总时间
-gcold 【老年代垃圾回收统计】
OGCMN:老年代最小容量OGCMX:老年代最大容量OGC:当前老年代大小OC:老年代大小YGC:年轻代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收消耗时间GCT:垃圾回收消耗总时间
-gcoldcapacity 【老年代空间统计】
MCMN:最小元数据容量MCMX:最大元数据容量MC:当前元数据空间大小 CCSMN:最小压缩类空间大小CCSMX:最大压缩类空间大小CCSC:当前压缩类空间大小YGC:年轻代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收消耗时间GCT:垃圾回收消耗总时间
-gcmatecapacity 【元数据空间统计】
-compiler 【JIT编译过的方法,耗时等】
-printcompilation 【输出以及被JIT编译的方法】
option参数
用于指定输出统计数据的周期,单位为毫秒。即:查询间隔
interval参数
用于指定查询的总次数
count参数
可以在输出信息前加上一个Timestamp列,显示程序的运行时间。单位:秒
我们执行jstat -gc -t 13152 1000 10,这代表1秒打印出1行,一共10行,-t代表打印出Timestamp总运行时间,结果如下所示:
上方红色框框中代表Timestamp,而蓝色框框中代表垃圾回收时间,单位都是秒,如果让红色框框中的某两个值相减,假设这个值是num1,然后让对应行的蓝色框框中的另外两个值相减,假设这个值是num2,之后让num2/num1,得出的差值就是上述所说的GC时间占运行时间的比例虽然这种方式比较繁琐,但是在项目部署之后就需要使用命令行去看了,就没有可视化界面了,所以这种方式也要会
经验
-t参数
可以在周期性数据输出时,输出多少行数据后输出一个表头信息
-h参数
jstat:查看JVM统计信息
jinfo (Configuration Inof for Java) 查看虚拟机配置参数信息,也可以动态调整虚拟机的配置参数
可以查看由System.getProperties()取得的参数
jinfo -sysprops 进程id
查看我们自己设置或者默认的参数信息
jinfo -flags 进程id
查看某个java进程的具体参数信息
jinfo -flag 参数名称 进程id
查看
查看被标记为 manageable的参数:java -XX:printFlagsFinal -version
jinfo不仅可以查看运行时某一个Java虚拟机参数的实际取值,甚至可以在运行时修改部分参数,并使之立即生效。但是,并非所有参数都支持动态修改。参数只有被标记为manageable的flag可以被实时修改。其实,这个修改能力是极其有限的
jinfo -flag [+|-]参数名称 进程id
针对boolean类型
jinfo -flag 参数名称=参数值 进程id
针对非boolean类型
修改
查看所有JVM参数启动的初始值
java -XX:+PrintFlagsInitial
查看所有JVM参数的最终值
java -XX:+PrintFlagsFinal
查看那些已经被用户或者JVM设置过的详细的XX参数的名称和值
java -参数名称:+PrintCommandLineFlags
jinfo:实时查看和修改JVM配置参数
jmap(JVM Memory Map):作用一方面是获取dump文件(堆转储快照文件,二进制文件),它还可以获取目标Java进程的内存相关信息括Java堆各区域的使用情况、堆中对象的统计信息、类加载信息等。
生成Java堆转储快照:dump文件
特别的:-dump:live只保存堆中的存活对象
-dump
输出整个堆空间的详细信息,包括GC的使用、堆配置信息,以及内存的使用信息等
-heap
输出堆中对象的同级信息,包括类、实例数量和合计容量
特别的:-histo:live只统计堆中的存活对象
-histo
以ClassLoader为统计口径输出永久代的内存状态信息
仅linux/solaris平台有效
-permstat
显示在F-Queue中等待Finalizer线程执行finalize方法的对象
-finalizerinfo
当虚拟机进程对-dump选项没有任何响应时,可使用此选项强制执行生成dump文件
-F
jamp工具使用的帮助命令
C-h | -help
传递参数给jmap启动的jvm
-J <flag>
font color=\"#a23c73\
手动的方式
程序发生OOM时,导出应用程序当前堆快照
可以指定堆快照的保存位置
-XX:HeapDumpPath=<filename.hprof>
自动的方式
导出内存映像文件(主要作用)
jmap -heap 进程id
jmap -histo 进程id
显示堆内存相关信息
jmap -permstat 进程id
查看系统的ClassLoader信息
jmap -finalizerinfo
查看堆积在finalizer队列中的对象
使用
jmap:导出内存映像文件&内存使用情况
jhat(JVM Heap Analysis Tool)
jdk8、jdk9 中已经被删除,官方建议用VisualVM参数
jhat:JDK自带堆分析工具
jstack(JVM Stack Trace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。span style=\"font-size:inherit;\
在thread dump 中要留意下面几种状态:死锁: Deadlock等待资源: Wait on Condition等待获取监视器:Waiting on monitor entry 阻塞: Blocked执行中:Runnable暂停: Suspend对象等待中: Object.wati() 或者 TIMED_WAITING停止:Parked
\"Thread-1\" 线程名 prio=5 优先级=5tid=0x000000001fa9e000 线程idnid=0x2d64 线程对应的本地线程标识nidjava.lang.Thread.State: BLOCKED 线程状态
当正常输出的请求不被响应时,强制输出线程堆栈
option参数:-F
除堆栈外,显示关于锁的附加信息
option参数:-l
如果调用本地方法的话,可以显示C/C++的堆栈
option参数:-m
帮助操作
option参数:-h
jstack:打印JVM中线程快照
列出所有的JVM进程
jcmd -l
针对指定的进程,列出支持的所有具体命令
jcmd 进程号 help
显示指定进程的指令命令的数据
Thread.print 可以替换 jstack指令GC.class_histogram 可以替换 jmap中的-histo操作GC.heap_dump 可以替换 jmap中的-dump操作GC.run 可以查看GC的执行情况VM.uptime 可以查看程序的总执行时间,可以替换jstat指令中的-t操作VM.system_properties 可以替换 jinfo -sysprops 进程idVM.flags 可以获取JVM的配置参数信息
jcmd 进程号 具体命令
jcmd:多功能命令行
jstatd:远程主机信息收集
JVM监控及诊断工具-命令行
JDK5开始,JDK自带的Java监控和管理控制台用于对JVM中内存、线程和类等的监控,是一个基于JMX(java management extensions)的GUI性能监控工具。
在jdk安装目录中找到jconsole.exe,双击该可执行文件就可以
打开DOS窗口,直接输入jconsole就可以了
启动
使用JConsole连接一个正在本地系统运行的JVM,并且执行程序的和运行JConsole的需要是同一个用户。JConsole使用文件系统的授权通过RMI连接起链接到平台的MBean的服务器上。这种从本地连接的监控能力只有Sun的JDK具有。
Local
使用下面的URL通过RMI连接器连接到一个JMX代理,service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi。JConsole为建立连接,需要在环境变量中设置mx.remote.credentials来指定用户名和密码,从而进行授权。
Remote
使用一个特殊的URL连接JMX代理。一般情况使用自己定制的连接器而不是RMI提供的连接器来连接JMX代理,或者是一个使用JDK1.4的实现了JMX和JMX Rmote的应用
Advanced
三种连接方式
Jconsole
监控本地Java进程的CPU、类、线程等
本地连接
1-确定远程服务器的ip地址
2-添加JMX(通过JMX技术具体监控远程服务器哪个Java进程)
3-修改bin/catalina.sh文件,连接远程的tomcat
4-在…/conf中添加jmxremote.access和jmxremote.password文件
5-将服务器地址改成公网ip地址
6-设置阿里云安全策略和防火墙策略
7-启动tomcat,查看tomcat启动日志和端口监听
8-JMX中输入端口号、用户名、密码登录
远程连接
连接方式
1.生成/读取堆内存快照
2.查看JVM参数和系统属性
3.查看运行中的虚拟机进程
4.生成/读取线程快照
5.程序资源的实时监控
JMX代理连接
远程环境监控
CPU分析和内存分析
6.其他功能
主要功能
Visual VM
MAT(Memory Analyzer Tool)工具是一款功能强大的Java堆内存分析器。可以用于font color=\"#e74f4c\
dump文件内存
说明
获取推 dump 文件
展示了各个类的实例数目以及这些实例的Shallow heap【浅堆】或者Retained heap【深堆】的总和
histogram
查看系统中的Java线程
查看局部变量的信息
thread overview
with outgoing references : 我引用了谁
with incoming references : 谁引用了我
获得对象互相引用的关系
一个对象所消耗的内存
shallow heap(浅堆)
对象保留集中所有对象的浅堆纸盒
保留集(Retained Set): 只有能被回收的对象才会被包含,例如C对象被A、B对象同时引用,C则不包含在A的保留集中。
保留集(Retained Set)
当前深堆大小 = 当前对象的浅堆大小 + 对象中所包含对象的深堆大小
retained heap (深堆)
对象的实际大小 >= 对象的深堆大小
对象的大小
浅堆与深堆
支配树的概念来自于图论
MAT里的支配树
支配树(Dominator Tree)
分析堆 dump 文件
案例:Tomcat堆溢出分析
SELECT子句
FROM子句
WHERE子句
内置对象与方法
支持使用OQL语言查询对象信息
Eclipse MAT
特点
对方法调用的分析可以帮助您了解应用程序正在做什么,并找到提高其性能的方法
方法调用
通过分析堆上对象、引用链和垃圾收集能帮您修复内存泄露问题,优化内存使用
内存分配
JProfiler提供多种针对线程和锁的分析视图助您发现多线程问题
线程和锁
许多性能问题都发生在更高的语义级别上。例如,对于JDBC调用,您可能希望找出执行最慢的SQL语句。JProfiler支持对这些子系统进行集成分析
高级子系统
instrumentation重构模式Sampling抽样模式
数据采集方式
遥感监测 Telemetries
内存视图 Live Memory
堆遍历 heap walker
cpu视图 cpu views
线程视图 threads
监视器&锁 Monitors&locks
具体使用
JProfiler
具体操作查看官方文档即可
Arthas
历史
功能:实时监控 JVM运行时的状态
事件类型
方式1:使用-XX:StartFlightRecording=参数
方式2:使用jcmd的JFR.*子命令
具体使用:
1、启动飞行记录仪
2、启动飞行记录
3、 正式启动
方式3:JMC的JFR插件
启动方式
Java Flight Recorder
Java Misssion Control
其他工具
JVM监控及诊断工具-GUI
比较稳定,后续版本基本不会变化
以-开头
直接在DOS窗口中运行java或者java -help可以看到所有的标准选项
各种选项
server
在32位Windows系统上,默认使用Client类型的JVM。要想使用Server模式,则机器配置至少有2个以上的CPU和2G以上的物理内存。 client模式适用于对内存要求较小的桌面应用程序,默认使用Serial串行垃圾收集器
client
-server & -client
类型一:标准参数选项
非标准化参数
功能还是比较稳定的。但官方说后续版本可能会变更
以-X开头
只使用解释器:所有字节码都被解释执行,这个模式的速度是很慢的
-Xint
只使用编译器:所有字节码第一次使用就被编译成本地代码,然后在执行
-Xcomp
混合模式:这是默认模式,刚开始的时候使用解释器慢慢解释执行,后来让JIT即时编译器根据程序运行的情况,有选择地将某些热点代码提前编译并缓存在本地,在执行的时候效率就非常高了
-Xmixed
JVM的JIT编译模式相关的选项
-Xms<size> 设置初始Java堆大小,等价于-XX:InitialHeapSize
-Xmx<size> 设置最大Java堆大小,等价于-XX:MaxHeapSize
-Xss<size> 设置Java线程堆栈大小,等价于-XX:ThreadStackSize
-Xmx -Xms -Xss属于XX参数?
类型二:-X参数选项
使用的最多的参数类型
这类选项属于实验性,不稳定
以-XX开头
用于开发和调试JVM
作用
-XX:+<option> 表示启用option属性
-XX:-<option>表示禁用option属性
例子
Boolean类型格式
子类型1:数值型格式-XX:<option>=<number>
子类型2:非数值型格式-XX:<name>=<string>
非Boolean类型格式(key-value类型)
分类
输出所有参数的名称和默认值
默认不包括Diagnostic和Experimental的参数(可以配合-XX:+UnlockDiagnosticVMOptions和-XX:UnlockExperimentalVMOptions使用)
-XX:+PrintFlagsFinal
类型三:-XX参数选项
JVM参数选择
Eclipes
IDEA
java -Xms50m -Xmx50m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -jar demo.jar
运行jar包
Linux系统下可以在tomcat/bin/catalina.sh中添加类似如下配置:JAVA_OPTS=\"-Xms512M -Xmx1024M\"
Windows系统下载catalina.bat中添加类似如下配置:set \"JAVA_OPTS=-Xms512M -Xmx1024M\"
通过Tomcat运行war包
使用jinfo -flag <name>=<value> <pid>设置非Boolean类型参数
使用jinfo -flag [+|-]<name> <pid>设置Boolean类型参数
程序运行过程中
添加JVM参数选项
可以让程序运行前打印出用户手动设置或者JVM自动设置的XX选项
-XX:+PrintCommandLineFlags
表示打印出所有XX选项的默认值
-XX:+PrintFlagsInitial
表示打印出XX选项在运行程序时生效的值
打印JVM的参数
-XX:+PrintVMOptions
打印设置的XX选项及值
等价于-XX:ThreadStackSize,设置每个线程的栈大小为128k
-Xss128k
栈
等价于-XX:InitialHeapSize,设置JVM初始堆内存为3500M
-Xms3550m
等价于-XX:MaxHeapSize,设置JVM最大堆内存为3500M
-Xmx3550m
设置年轻代大小为2G,即等价于-XX:NewSize=2g -XX:MaxNewSize=2g,也就是设置年轻代初始值和年轻代最大值都是2G
官方推荐配置为整个堆大小的3/8
-Xmn2g
设置年轻代初始值为1024M
-XX:NewSize=1024m
设置年轻代最大值为1024M
-XX:MaxNewSize=1024m
设置年轻代中Eden区与一个Survivor区的比值,默认为8
-XX:SurvivorRatio=8
自动选择各区大小比例,默认开启
默认开启,将会导致Eden区和Survivor区的比例自动分配,因此也会引起我们默认值-XX:SurvivorRatio=8失效,所以真实比例可能不是8,比如可能是6等
-XX:SurvivorRatio=8显示使用Eden区和Survivor区的比例,那就使用我自己的没有显示使用Eden区和Survivor区的比例,无论打开或者关闭-XX:+UseAdaptiveSizePolicy,都会自动设置Eden区和Survivor区的比例
-XX:+UseAdaptiveSizePolicy
设置老年代与年轻代(包括1个Eden区和2个Survivor区)的比值,默认为2
-XX:NewRatio=2
设置让大于此阈值的对象直接分配在老年代,单位为字节
只对Serial、ParNew收集器有效
-XX:PretenureSizeThreadshold=1024
新生代每次MinorGC后,还存活的对象年龄+1,当对象的年龄大于设置的这个值时就进入老年代
-XX:MaxTenuringThreshold=15
让JVM在每次MinorGC后打印出当前使用的Survivor中对象的年龄分布
-XX:+PrintTenuringDistribution
-XX:TargetSurvivorRatio
堆内存
设置永久代初始值为256M
-XX:PermSize=256m
设置永久代最大值为256M
-XX:MaxPermSize=256m
永久代
初始空间大小
-XX:MetaspaceSize
最大空间,默认没有限制
-XX:MaxMetaspaceSize
使用压缩对象指针
-XX:+UseCompressedOops
使用压缩类指针
-XX:+UseCompressedClassPointers
设置Klass Metaspace的大小,默认1G
-XX:CompressedClassSpaceSize
元空间
方法区
指定DirectMemory容量,若未指定,则默认与Java堆最大值一样
-XX:MaxDirectMemorySize
直接内存
堆、栈、方法区等内存大小设置
表示在内存出现OOM的时候,生成Heap转储文件,以便后续分析,-XX:+HeapDumpBeforeFullGC和-XX:+HeapDumpOnOutMemoryError只能设置1个
-XX:+HeapDumpOnOutMemoryError
表示在出现FullGC之前,生成Heap转储文件,以便后续分析,-XX:+HeapDumpBeforeFullGC和-XX:+HeapDumpOnOutMemoryError只能设置1个,请注意FullGC可能出现多次,那么dump文件也会生成多个(程序结束之前也会生成)
-XX:+HeapDumpBeforeFullGC
指定heap转存文件的存储路径,如果不指定,就会将dump文件放在当前目录中
-XX:HeapDumpPath=<path>
指定一个可行性程序或者脚本的路径,当发生OOM的时候,去执行这个脚本
-XX:OnOutOfMemoryError
OutOfMemory相关的选项
输出日志信息,默认输出的标准输出
可以独立使用
-verbose:gc
等同于-verbose:gc(表示打开简化的日志)
-XX:+PrintGC
在发生垃圾回收时打印内存回收详细的日志,并在进程退出时输出当前内存各区域的分配情况
-XX:+PrintGCDetails
程序启动到GC发生的时间秒数
不可以独立使用,需要配合-XX:+PrintGCDetails使用
-XX:+PrintGCTimeStamps
输出GC发生时的时间戳(以日期的形式,例如:2013-05-04T21:53:59.234+0800)
不可以独立使用,可以配合-XX:+PrintGCDetails使用
-XX:+PrintGCDateStamps
每一次GC前和GC后,都打印堆信息
-XX:+PrintHeapAtGC
把GC日志写入到一个文件中去,而不是打印到标准输出中
-XIoggc:<file>
常用参数
监控类的加载
-XX:TraceClassLoading
打印GC时线程的停顿时间
-XX:PrintGCApplicationStoppedTime
垃圾收集之前打印出应用未中断的执行时间
-XX:+PrintGCApplicationConcurrentTime
记录回收了多少种不同引用类型的引用
-XX:+PrintReferenceGC
启用GC日志文件的自动转储
-XX:+UseGCLogFileRotation
GC日志文件的循环数目
-XX:NumberOfGCLogFiles=1
控制GC日志文件的大小
-XX:GCLogFileSize=1M
其他参数
%t 代表时间
java -jar -Xloggc:./gc-%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M microservice-eureka-server.jar
-Xloggc:d:/gc-cms-%t.log -Xms50M -Xmx50M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
CMS
-Xloggc:d:/gc-g1-%t.log -Xms50M -Xmx50M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UseG1GC
G1
实例
GC日志相关选项
禁用hotspot执行System.gc(),默认禁用
-XX:+DisableExplicitGC
指定代码缓存的大小
-XX:ReservedCodeCacheSize=<n>[g|m|k]、-XX:InitialCodeCacheSize=<n>[g|m|k]
使用该参数让jvm放弃一些被编译的代码,避免代码缓存被占满时JVM切换到interpreted-only的情况
-XX:+UseCodeCacheFlushing
开启逃逸分析
-XX:+DoEscapeAnalysis
开启偏向锁
-XX:+UseBiasedLocking
开启使用大页面
-XX:+UseLargePages
打印TLAB的使用情况
-XX:+PrintTLAB
设置TLAB大小
-XX:TLABSize
常用的JVM参数选项
通过Java代码获取JVM参数
JVM运行时参数
GC类型
老年代使用 CMS GC
DefNew代表新生代使用Serial GC,然后Tenured代表老年代使用Serial Old GC
新生代使用 Serial GC
不同GC分类的GC细节
Minor GC
Full GC
日志分类
垃圾回收器
GC前后情况
GC时间
GC日志结构剖析
日志打印时间 日期格式 如 2013-05-04T21:53:59.234+0800
2020-11-20T17:19:43.265-0800
gc发生时,Java虚拟机启动以来经过的秒数
0.822:
发生了一次垃圾回收,这是一次Minior GC。它不区分新生代还是老年代GC,括号里的内容是gc发生的原因,这里的Allocation Failure的原因是新生代中没有足够区域能够存放需要分配的数据而失败
[GC(Allocation Failure)
Serial收集器:Default New Generation 显示Defnew
ParNew收集器:ParNew
Parallel Scanvenge收集器:PSYoung
老年代和新生代同理,也是和收集器名称相关
PSYoungGen:表示GC发生的区域,区域名称与使用的GC收集器是密切相关的
如果是新生代,总容量则会显示整个新生代内存的9/10,即eden+from/to区
如果是老年代,总容量则是全身内存大小,无变化
76800K->8433K(89600K):GC前该内存区域已使用容量->GC后盖区域容量(该区域总容量)
[PSYoungGen:76800K->8433K(89600K)
在显示完区域容量GC的情况之后,会接着显示整个堆内存区域的GC情况:GC前堆内存已使用容量->GC后堆内存容量(堆内存总容量),并且堆内存总容量 = 9/10 新生代 + 老年代,然后堆内存总容量肯定小于初始化的内存大小
虽然本次是Minor GC,只会进行新生代的垃圾收集,但是也肯定会打印堆中总容量相关信息
76800K->8449K(294400K)
整个GC所花费的时间,单位是秒
user:指CPU工作在用户态所花费的时间
sys:指CPU工作在内核态所花费的时间
real:指在此次事件中所花费的总时间
Minor GC 日志解析
日志打印时间 日期格式 如 2013-05-04T21:53:59.234+0800
括号中是gc发生的原因,原因:Metaspace区不够用了。除此之外,还有另外两种情况会引起Full GC,如下:Full GC(FErgonomics) 原因:JVM自适应调整导致的GCFull GC(System) 原因:调用了System.gc()方法
Full GC(Metadata GCThreshold)
Serial收集器:Default New Generation 显示Defnew
Parallel Scanvenge收集器:PSYoung
100082K->0K(89600K):GC前该内存区域已使用容量->GC后盖区域容量(该区域总容量)
[PSYoungGen: 100082K->0K(89600K)]
老年代区域没有发生GC,因此本次GC是metaspace引起的
ParOldGen:32K->9638K(204800K)
10114K->9638K(294400K)
metaspace GC 回收2K空间
[Meatspace:20158K->20156K(1067008K)]
Full GC 日志解析
GC日志格式
GCEasy
安装
GCViewer
GC日志分析工具
分析GC日志
JVM性能监控与调优
![JVM性能监控与调优](https://www.processon.com/chart_image/template/thumb/668cd1c3bfa6815821a8cc6e.png?tid=668bd630f1f0be6585848d8c)
收藏
0 条评论
回复 删除
下一页