JVM常见的命令及工具
前言
个人认为的一个JVM的问题的解决方法论: 首先有JVM的知识储备是基础,然后有相关的数据(堆、GC日志等)支撑为依据,最后使用工具去定位和解决问题是手段。至今仍然没有出现一个完美的垃圾收集器,所以根据自己服务器的请求量和并发量以及自己服务器或者客户端的角色来选择合适的收集器或者设置一些合适的参数尤为重要,合适的才是最好的。同时,当线上出现各类JVM问题的时候,如果没有一些提前的储备,就很容易变得不知所措,实践出真知是老祖宗很早就明白的道理。本文主要介绍常见的JVM命令以及参数,这些是排查GC问题的基础。
JVM 工具命令
JVM命令的来源这里不做过多无用介绍,仅了解它是供我们监视和处理故障的工具命令,如下表格所列:
命令行工具 | 说明 |
---|---|
jps | 查询正在运行的JVM进程id,(命令单一且简单且重要) |
jstat | 实时显示本地或远程 JVM 进程中类装载、内存、垃圾收集等数据 |
jinfo | 查询当前运行的JVM属性和参数的值 |
jmap | 显示&生成当前Java堆的详细信息 |
jhat | 用于分析使用jmap和生成dump文件(几乎不用,几乎无人用) |
jstack | 生成当前JVM所有线程快照(每条线程正在执行的方法)可以定位线程停顿的原因 |
jstat 虚拟机监视工具
jstat 用来监视虚拟机各种运行状态的工具,通过它可以看出类装载、内存变化、垃圾收集情况等数据,经常被用来定位JVM的问题的首先工具。
格式:
举个例子: 查看JVM进程为400的gc情况,每隔200ms输出一次,一共输出10次结束。 (200和10 都可以省略)
jstat [ option pid [interval[s|ms] [count]] ]
选项:
-gc 监视Java堆状况,包括Eden区、2个survivor区、老年代、永久代的容量、已用空间、GC时间等基本信息
-gccapacity 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大和最小空间
-gcutil 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
-gcnew 监视新生代GC的状况
-gcnewcapacity 监视内容与-gcnew基本相同,输出主要关注使用到的最大和最小空间
-gcold 监视老年代GC的状况
-gcoldcapacity 监视内容与-gcold基本相同,输出主要关注使用到的最大和最小空间
-gcpermcapacity 输出永久代使用到的最大和最小空间
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已经被JIT编译的方法
-class 监视类装载、卸载数、总空间及类装载所耗费的时间
举个例子: 查看JVM进程为400的gc情况,每隔200ms输出一次,一共输出10次结束。 (200和10 都可以省略)
jstat -gcutil 400 200 10
jinfo JVM虚拟机参数查看和修改部分参数工具
jinfo 可以实时地査看和调整虚拟机的各项参数值的。(它可以在JVM运行期间修改JVM的值)
格式:
jinfo [ option ] pid
它的选项比较少,大多数情况我们只需要关注 -flag 这个参数即可
查看JVM进程为400的 CMSInitiatingOccupancyFraction 值
jinfo -flag CMSInitiatingOccupancyFraction 400
修改JVM进程为400的 CMSInitiatingOccupancyFraction 值为90
jinfo -flag CMSInitiatingOccupancyFraction=90 400
jmap JVM 的内存映像工具
jmap 是被用来dump我们的堆文件的命令,这个命令在生产环境上理论上不允许直接操作,因为它是会触发一次FGC之后将堆中剩余的对象转储起来,生产环境直接使用会导致 STW 效应,如果是核心机器会有短暂的服务不可用,如果真需要堆文件,一般联系运维将此机器隔离,然后确认没有流量了再操作。
格式:
jmap [ option ] vmid
选项:
-dump 生成Java堆转储快照。格式为:-dump:[live,]format=b,file=file_name ,live子参数说明是否只dump出存活的对象,format=b代表存下来是二进制 file=file_name 是存储下来的文件名称,具体的操作见下面示例。【重要】
-finalizerinfo 显示在F-Queue中等待Finalizer线程执行finalize方法的对象。只在Linux / Solaris平台下有效
-heap 显示Java堆详细信息,如使用哪种回收器、参数配置、分代状况等,只在Linux/ Solaris平台下有效
-histo 显示堆中对象统计信息.包括类、实例数量和合计容量
示例:
1、转储进程200的存活的堆信息,使用二进制格式,名称为filename
jmap -dump:live,format=b,file=filename 200
2、打印heap的概要信息,GC使用的算法,heap的配置及使用情况,可以用此来判断内存目前的使用情况以及垃圾回收情况
jmap -heap 30
jstack 堆栈监视工具
jstack 命令可以生成虚拟机当前时刻的线程快照,所谓线程快些好就是当前虚拟机内每一条线程正在执行的方法堆栈的集合。可以方便的帮助我们排查到线程卡顿的原因,比如死锁、死循环、获取资源链接的时间过长等。
格式:
jstack [ option ] vmid
选项:
-F 当正常输出的请求不被响应时,强制输出线程堆栈
-l 除堆栈外,显示关于锁的附加信息
-m 如果调用到本地方法的话,可以显示C/C++的堆栈
示例:查看虚拟机进程为400的锁的附加信息
jstack -l 400
JVM 常见参数
参数名 | 含义 |
---|---|
-Xmx | 指定java程序的最大堆内存 |
-Xms | 指定最小堆内存, 通常设置成跟最大堆内存一样,减少GC |
-Xmn | 设置年轻代大小。整个堆大小=年轻代大小 + 年老代大小。所以增大年轻代后,将会减小年老代大小 |
-Xss | 指定线程的最大栈空间, 此参数决定了java函数调用的深度, 值越大调用深度越深, 若值太小则容易出栈溢出错误(StackOverflowError) |
-XX:PermSize | 指定方法区(永久区)的初始值,默认是物理内存的1/64, 在Java8永久区移除, 代之的是元数据区, 由-XX:MetaspaceSize指定 |
-XX:MaxPermSize | 指定方法区的最大值, 默认是物理内存的1/4, 在java8中由-XX:MaxMetaspaceSize指定元数据区的大小 |
-XX:NewRatio=n | 年老代与年轻代的比值,-XX:NewRatio=2, 表示年老代与年轻代的比值为2:1 |
-XX:SurvivorRatio=n | Eden区与Survivor区的大小比值,-XX:SurvivorRatio=8表示Eden区与Survivor区的大小比值是8:1:1,因为Survivor区有两个(from, to) |
-XX:MaxTenuringThreshold | 设置经过多少次YGC之后对象晋升老年代,默认情况下,JVM会动态调整这个值(所以千万别认为它就是15)。它的最大值是15,因为对象头中年龄是4字节表示的,1111=15 |
-XX:+UseConcMarkSweepGC | 设置老年代的收集器为CMS |
-XX:CMSInitiatingOccupancyFraction | 设置还剩余多少堆(百分比)时进行CMS收集,默认68%。如果年老代增长缓慢,可以增加此值 |
-XX:CMSFullGCsBeforeCompaction=5 | 由于CMS不对内存空间进行整理,此值设置运行多少次Full GC以后对内存空间进行整理。设置此参数可能导致promotion failure(晋升失败) |
-XX:+UseCMSCompactAtFullCollection | Full GC后对年老代进行整理。可能会影响性能,但是可以消除碎片。默认true |
小结
本文主要介绍了一些处理线上JVM问题的常见的工具命令以及JVM的常见配置参数,仅作为一篇工具使用介绍文章,后续将会以实际的案例去将这些知识点使用起来。