JVM调优命令大全及常用命令工具和实战步骤

1JVM参数

1.1 标准参数

所谓的标准参数,就是不会随着我们JDK 变化而变化版本的参数
这种参数可以通过Java -help查看(和Java -version使用方式一样)

Microsoft Windows [版本 10.0.22000.795]
(c) Microsoft Corporation。保留所有权利。

C:\Users\zwq>java -help
用法: java [-options] class [args...]
           (执行类)
   或  java [-options] -jar jarfile [args...]
           (执行 jar 文件)
其中选项包括:
    -d32          使用 32 位数据模型 (如果可用)
    -d64          使用 64 位数据模型 (如果可用)
    -server       选择 "server" VM
                  默认 VM 是 server.

    -cp <目录和 zip/jar 文件的类搜索路径>
    -classpath <目录和 zip/jar 文件的类搜索路径>; 分隔的目录, JAR 档案
                  和 ZIP 档案列表, 用于搜索类文件。
    -D<名称>=<>
                  设置系统属性
    -verbose:[class|gc|jni]
                  启用详细输出
    -version      输出产品版本并退出
    -version:<>
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  需要指定的版本才能运行
    -showversion  输出产品版本并继续
    -jre-restrict-search | -no-jre-restrict-search
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  在版本搜索中包括/排除用户专用 JRE
    -? -help      输出此帮助消息
    -X            输出非标准选项的帮助
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  按指定的粒度启用断言
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  禁用具有指定粒度的断言
    -esa | -enablesystemassertions
                  启用系统断言
    -dsa | -disablesystemassertions
                  禁用系统断言
    -agentlib:<libname>[=<选项>]
                  加载本机代理库 <libname>, 例如 -agentlib:hprof
                  另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
    -agentpath:<pathname>[=<选项>]
                  按完整路径名加载本机代理库
    -javaagent:<jarpath>[=<选项>]
                  加载 Java 编程语言代理, 请参阅 java.lang.instrument
    -splash:<imagepath>
                  使用指定的图像显示启动屏幕
有关详细信息, 请参阅 http://www.oracle.com/technetwork/java/javase/documentation/index.html。

1.2 -X 参数(非标准参数)

在jdk某个版本中存在,可能会随着版本变更移除,在标准参数的基础上进行扩展的参数,输入“java -X”命令,能够获得当前JVM支持的所有非标准参数列表(你会发现,其实并不多哦)。

C:\Users\zwq>java -X
    -Xmixed           混合模式执行(默认)
    -Xint             仅解释模式执行
    -Xbootclasspath:<; 分隔的目录和 zip/jar 文件>
                      设置引导类和资源的搜索路径
    -Xbootclasspath/a:<; 分隔的目录和 zip/jar 文件>
                      附加在引导类路径末尾
    -Xbootclasspath/p:<; 分隔的目录和 zip/jar 文件>
                      置于引导类路径之前
    -Xdiag            显示附加诊断消息
    -Xnoclassgc        禁用类垃圾收集
    -Xincgc           启用增量垃圾收集
    -Xloggc:<file>    将 GC 状态记录在文件中(带时间戳)
    -Xbatch           禁用后台编译
    -Xms<size>        设置初始 Java 堆大小
    -Xmx<size>        设置最大 Java 堆大小
    -Xss<size>        设置 Java 线程堆栈大小
    -Xprof            输出 cpu 分析数据
    -Xfuture          启用最严格的检查,预计会成为将来的默认值
    -Xrs              减少 Java/VM 对操作系统信号的使用(请参阅文档)
    -Xcheck:jni       对 JNI 函数执行其他检查
    -Xshare:off       不尝试使用共享类数据
    -Xshare:auto      在可能的情况下使用共享类数据(默认)
    -Xshare:on        要求使用共享类数据,否则将失败。
    -XshowSettings    显示所有设置并继续
    -XshowSettings:system
                      (仅限 Linux)显示系统或容器
                      配置并继续
    -XshowSettings:all
                      显示所有设置并继续
    -XshowSettings:vm 显示所有与 vm 相关的设置并继续
    -XshowSettings:properties
                      显示所有属性设置并继续
    -XshowSettings:locale
                      显示所有与区域设置相关的设置并继续

-X 选项是非标准选项。如有更改,恕不另行通知。

1.3 -XX 参数(非Stable参数)

此类参数各个jvm实现会有所不同(用的最多:JVM调优),将来可能会随时取消,需要慎重使用;
以-XX表示的非Stable参数, JVM(Hotspot)中主要的参数可以大致分为3类

**性能参数(Performance Options):**用于JVM的性能调优和内存分配控制,如初始化内存大小的设置;

**行为参数(Behavioral Options):**用于改变JVM的基础行为,如GC的方式和算法的选择;

**调试参数(Debugging Options):**用于监控、打印、输出等jvm参数,用于显示jvm更加详细的信息;

对于非Stable参数,使用方法有4种:
-XX:+ 启用选项

-XX:- 不启用选项

-XX:= 给选项设置一个数字类型值,可跟单位,例如 32k, 1024m, 2g

-XX:= 给选项设置一个字符串值,例如-XX:HeapDumpPath=./dump.core

1.3.1性能参数

性能参数往往用来定义内存分配的大小和比例,相比于行为参数和调试参数,一个比较明显的区别是性能参数后面往往跟的有数值,常用如下:

参数及其默认值描述
-XX:NewSize=2.125m新生代对象生成时占用内存的默认值
-XX:MaxNewSize=size新生成对象能占用内存的最大值
-XX:MaxPermSize=64m方法区所能占用的最大内存(非堆内存)
-XX:PermSize=64m方法区分配的初始内存
-XX:MaxTenuringThreshold=15对象在新生代存活区切换的次数(坚持过MinorGC的次数,每坚持过一次,该值就增加1),大于该值会进入老年代(年龄阈值)
-XX:MaxHeapFreeRatio=70GC后java堆中空闲量占的最大比例,大于该值,则堆内存会减少
-XX:MinHeapFreeRatio=40GC后java堆中空闲量占的最小比例,小于该值,则堆内存会增加
-XX:NewRatio=2新生代内存容量与老生代内存容量的比例
-XX:ReservedCodeCacheSize= 32m保留代码占用的内存容量
-XX:ThreadStackSize=512设置线程栈大小,若为0则使用系统默认值
-XX:LargePageSizeInBytes=4m设置用于Java堆的大页面尺寸
-XX:PretenureSizeThreshold= size大于该值的对象直接晋升入老年代(这种对象少用为好)
-XX:SurvivorRatio=8Eden区域Survivor区的容量比值,如默认值为8,代表Eden:Survivor1:Survivor2=8:1:1

1.3.2行为参数

行为参数主要用来选择使用什么样的垃圾收集器组合,以及控制运行过程中的GC策略等

参数及其默认值描述
-XX:+UseSerialGC启用串行GC,即采用Serial+Serial Old模式
-XX:+UseParallelGC启用并行GC,即采用Parallel Scavenge+Serial Old收集器组合(-Server模式下的默认组合)
-XX:GCTimeRatio=99设置用户执行时间占总时间的比例(默认值99,即1%的时间用于GC)
-XX:MaxGCPauseMillis=time设置GC的最大停顿时间(这个参数只对Parallel Scavenge有效)
-XX:+UseParNewGC使用ParNew+Serial Old收集器组合
-XX:ParallelGCThreads设置执行内存回收的线程数,在+UseParNewGC的情况下使用
-XX:+UseParallelOldGC使用Parallel Scavenge +Parallel Old组合收集器
-XX:+UseConcMarkSweepGC使用ParNew+CMS+Serial Old组合并发收集,优先使用ParNew+CMS,当用户线程内存不足时,采用备用方案Serial Old收集。
-XX:-DisableExplicitGC禁止调用System.gc();但jvm的gc仍然有效
-XX:+ScavengeBeforeFullGC新生代GC优先于Full GC执行

1.3.3调试参数

调试参数,主要用于监控和打印GC的信息

参数及其默认值描述
-XX:-CITime打印消耗在JIT编译的时间
-XX:ErrorFile=./hs_err_pid.log保存错误日志或者数据到文件中
-XX:-ExtendedDTraceProbes开启solaris特有的dtrace探针
-XX:HeapDumpPath=./java_pid.hprof指定导出堆信息时的路径或文件名
-XX:-HeapDumpOnOutOfMemoryError当首次遭遇OOM时导出此时堆中相关信息
-XX:OnError=“;”出现致命ERROR之后运行自定义命令
-XX:OnOutOfMemoryError=“;”当首次遭遇OOM时执行自定义命令
-XX:-PrintClassHistogram遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同
-XX:-PrintConcurrentLocks遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同
-XX:-PrintCommandLineFlags打印在命令行中出现过的标记
-XX:-PrintCompilation当一个方法被编译时打印相关信息
-XX:-PrintGC每次GC时打印相关信息
-XX:-PrintGC Details每次GC时打印详细信息
-XX:-PrintGCTimeStamps打印每次GC的时间戳
-XX:-TraceClassLoading跟踪类的加载信息
-XX:-TraceClassLoadingPreorder跟踪被引用到的所有类的加载信息
-XX:-TraceClassResolution跟踪常量池
-XX:-TraceClassUnloading跟踪类的卸载信息
-XX:-TraceLoaderConstraints跟踪类加载器约束的相关信息

1.4其他参数(一定要背下来)

-Xms100M  等价于  -XX:InitialHeapSize=100M 堆的初始化大小
-Xmx100M  等价于  -XX:MaxHeapSize=100M 堆的最大内存
-Xss100k  等价于  -XX:ThreadStackSize=100k 虚拟机栈的大小 默认是1m

2设置参数的方式

  1. 开发工具
    IDEA 、Eclipse 在run configuration 里设置VM option
    运行jar包, java -XX:+UseG1GC xxx.jar
  2. 线上环境
    web容器:Tomcat, startup.sh -> catalina.sh(卡特琳娜) 里设置JVM 参数
    jsp + jinfo 查看某个java进程的参数,然后再调整设置
  3. 真实调优
    java -XX:+UseG1GC xxx.jar

3 五大常用命令(一定要背下来)

3.1 JPS

查看java进程id

查看当前系统上,正在运行的java 进程 id列表和运行的类全限定名

在这里插入图片描述

3.2 jinfo

查看参数

  1. 实时查看某个进程id的jvm 参数
    在这里插入图片描述
  2. 查看某个进程id的所有jvm参数
    在这里插入图片描述
  3. 修改我们可以 manageable 热更新的参数
    在这里插入图片描述

3.3 jstat

查看性能
类加载、内存、垃圾收集情况、 JIT 实时编译的运行时数据

虚拟机统计信息监控工具,本地或者远程虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据

在这里插入图片描述

参数解释:

option 参数解释
-class显示ClassLoad的相关信息
-compiler显示JIT编译的相关信息
-gc显示和gc相关的堆信息-
-gccapacity显示各个代的容量以及使用情况
-gccause显示垃圾回收的相关信息(通-gcutil),同时显示最后一次或当前正在发生的垃圾回收的诱因
-gcnew显示新生代的信息
-gcnewcapacity显示新生代大小和使用情况
-gcold显示老年代和永久代的信息
-gcoldcapacity显示老年代的大小
-gcpermcapacity显示永久代的大小
-gcutil显示垃圾收集信息
-printcompilation输出JIT编译的方法信息
参数解释
-t可以在打印的列上加上Timestamp列,用于显示系统运行的时间
-h可以在周期性数据的时候,可以在指定输出多少行以后输出一次表头
interval执行每次的间隔时间,单位为毫秒
count用于指定输出多少次记录,缺省则会一直打印

举几个例子:

  1. 查看类装载信息
    在这里插入图片描述
    jstat -class PID 1000 10 查看某个java进程的类装载信息,每1000毫秒输出一 次,共输出10次
    在这里插入图片描述
  2. 查看垃圾收集信息
    jstat -gc PID 1000 10
    在这里插入图片描述
参数解析
S0CSurvivor0(幸存者0区)大小(KB)
S1CSurvivor1(幸存者1区)大小(KB)
S0USurvivor0(幸存者0区)已使用大小(KB)
S1CSurvivor1(幸存者1区)以使用大小(KB)
ECEeden(伊甸区)大小(KB)
EUEden(伊甸区)已使用大小(KB)
OC老年代大小(KB)
OU老年代已使用大小 (KB)
OC老年代大小(KB)
OU老年代已使用大小(KB)
PCPerm永久代大小(KB)
PUPerm永久代已使用大小(KB)
YGC新生代GC个数
YGCT新生代GC的耗时(秒
FGCFull GC次数
FGCTFull GC耗时(秒)
GCTGC总耗时(秒)

C = Capacity 容量
U = Used 已使用的意思
P = permanent 永久代
S = Survivor 幸存者
Y = Young
T = time 时间
E = Eden

3.4 jstack 堆栈信息

查看线程堆栈信息

jstack pid
查看线程堆栈

在这里插入图片描述

3.5jmap

生成堆栈转储快照

The jmap command prints shared object memory maps or heap memory details of a specified process, core file, or remote debug server.

打印堆内存相关信息

jmap -heap PID

在这里插入图片描述
dump 堆内存相关信息

jmap -dump:format=b,file=heap.hprof 44808

要是在发生堆内存溢出的时候,能自动dump出该文件就好了

一般在开发中,JVM参数可以加上下面两句,这样内存溢出时,会自动dump出该文件

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof

-Xmx20M -Xms20M -XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=heap.hprof
启动,然后访问 localhost:9090/heap

在服务器
在tomcat启动参数中加入两个参数
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/export/tomcat/xxx/xx/heap.hprof

在排查的的时候

jmap -dump:format=b,file=heap.hprof 44808

一般dump下来的文件可以结合工具来分析

4调优常用工具

jconsole、jvisualvm、MAT 在分析Dump文件的时候用
GC Viewer 分析GC日志

4.1jconsole

Jconsole工具是JDK自带的可视化监控工具。查看java应用程序的运行情况、监控堆信息、永久区使用情况、类加载情况等等

命令行中输入:jconsole 即可

4.2jvisualvm

监控本地java进程
可监控本地java进程的CPU,类,线程等等。
监控远端java进程

比如监控客户端的tomcat

演示一下部署在阿里云服务器上的tomcat

(1)在visualvm中选中“远程”,右击“添加”
(2)主机名上写服务器的ip地址,比如31.100.39.63,然后点击“确定”
(3)右击该主机“31.100.39.63”,添加“JMX”[也就是通过JMX技术具体监控远端服务器哪个Java进程]
(4)要想让服务器上的tomcat被连接,需要改一下 bin/catalina.sh 这个文件

注意下面的8998不要和服务器上其他端口冲突

JAVA_OPTS=“$JAVA_OPTS -Dcom.sun.management.jmxremote - Djava.rmi.server.hostname=31.100.39.63 - Dcom.sun.management.jmxremote.port=8998 - Dcom.sun.management.jmxremote.ssl=false - Dcom.sun.management.jmxremote.authenticate=true - Dcom.sun.management.jmxremote.access.file=…/conf/jmxremote.access -Dcom.sun.management.jmxremote.password.file=…/conf/jmxremote.pass word”

(5)在 …/conf 文件中添加两个文件jmxremote.access和jmxremote.password
jmxremote.access 文件

guest readonly manager readwrite

jmxremote.password 文件

guest guest manager manager

授予权限 : chmod 600 *jmxremot*

(6)将连接服务器地址改为公网ip地址
(7)设置上述端口对应的阿里云安全策略和防火墙策略
(8)启动tomcat,来到bin目录

./startup.sh

(9)查看tomcat启动日志以及端口监听

tail -f ../logs/catalina.out lsof -i tcp:8080

(10)查看8998监听情况,可以发现多开了几个端口

lsof -i:8998 得到PID netstat -antup | grep PID

(11)在刚才的JMX中输入8998端口,并且输入用户名和密码则登录成功

端口:8998 用户名:manager 密码:manager

4.3 MAT

Java堆分析器,用于查找内存泄漏
Heap Dump,称为堆转储文件,是Java进程在某个时间内的快照
下载地址 :https://www.eclipse.org/mat/downloads.php

Dump信息包含的内容

  • All Objects
    Class, fifields, primitive values and references
  • All Classes
    Classloader, name, super class, static fifields
  • Garbage Collection Roots
    Objects defifined to be reachable by the JVM
  • Thread Stacks and Local Variables
    The call-stacks of threads at the moment of the snapshot, and per-frame information about local objects

获取Dump文件
手动

jmap -dump:format=b,file=heap.hprof 44808

自动
idea设置VM参数、或者运行jar包时 设置

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof

4.4使用MAT

Histogram
Histogram [ˈhɪstəɡræm] 柱状图 :可以列出内存中的对象,对象的个数及其大小

Class Name:类名称,java类名 Objects:类的对象的数量,这个对象被创建了多少个 Shallow Heap:一个对象内存的消耗大小,不包含对其他对象的引用 Retained Heap: 是shallow Heap的总和,即该对象被GC之后所能回收到内存的总和。

右击类名—>List Objects—>with incoming references—>列出该类的实例

右击Java对象名—>Merge Shortest Paths to GC Roots—>exclude all …—>找到GC Root以及原因

Leak[li:k] Suspects [səˈspekts]
查找并分析内存泄漏的可能原因

Reports—>Leak Suspects—>Details

Top Consumers

列出大对象

5调优实战分析

5.1生产环境事故

java 进程突然消失了

线上程序异常,首先你得知道Java 的异常体系,分别为 Exception、Error 两种体系,对于Exception我们程序员一般分为受检异常和非受检异常,大部分异常都能通过log文件分析。

Error异常体系发生的原因有jvm自身的bug,应用程序错误,jvm参数配置不当,服务器资源不足,jni调用错误等等。当我们JVM 出现致命错误,会生成一个错误的文件,hs_error_pid.log,里面有导致 JVM 崩溃的重要信息。

比如: 线程信息、所有线程信息、堆信息、gc相关记录

解决思路:

  1. 业务日志 没有错误
  2. JVM 错误日志
    hs_error_pid.log

可以通过设置以下这个参数,来指定错误日志路径
-XX:ErrorFile=./

通过分析我们的 jvm 错误日志定位问题,然后解决。

5.2程序监控调优

前提:java 应用程序必然是正常运行的。.

目的:减少GC 频率,减少Full GC

发现现象才去解决?比如说 CPU 飙升、内存飙升

  1. 打印dump文件分析堆内存
  2. 打印GC日志,分析日志文件

-Xms30m -Xmx30m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=heap1.hprof
-XX:+PrintGCDetails
-Xloggc:gc.log

  1. 定位问题
  2. 调节参数
  3. 观察结果
  4. 重复4、5步

5.3GC的次数频繁怎么办?

打印出GC日志,到底是minorGC频繁还是majorGC频繁,结合工具看一下
(1)适当增加堆内存的空间
(2)选择垃圾收集器不合适
(3)(如果是G1)停顿时间是否太严格,或者堆存的使用率可以调成高于45%

5.4几个面试问题

调优无非就是 减少GC次数、减少Full GC,提高应用程序的吞吐量

(1)内存泄漏与内存溢出的区别
内存泄漏:对象无法得到及时的回收,持续占用内存空间,从而造成内存空间的浪费。
内存溢出:内存泄漏到一定的程度就会导致内存溢出,但是内存溢出也有可能是大对象导致的。
(2)young gc会有stw吗?
不管什么 GC,都会有 stop-the-world,只是发生时间的长短。
(3)major gc和full gc的区别
major gc指的是老年代的gc,而full gc等于young+old+metaspace的gc。
(4)G1与CMS的区别是什么
CMS 用于老年代的回收,而 G1 用于新生代和老年代的回收。
G1 使用了 Region 方式对堆内存进行了划分,且基于标记整理算法实现,整体减少了垃圾碎片的产生。
(5)什么是直接内存
直接内存是在java堆外的、直接向系统申请的内存空间。通常访问直接内存的速度会优于Java堆。因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内存。
(6)不可达的对象一定要被回收吗?
即使在可达性分析法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑阶段”,要真正宣告一个对象死亡,至少要经历两次标记过程;可达性分法中不可达的对象被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行fifinalize 方法。当对象没有覆盖 fifinalize 方法,或 fifinalize 方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。
被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。
(7)方法区中的无用类回收
方法区主要回收的是无用的类,那么如何判断一个类是无用的类的呢?判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。
类需要同时满足下面 3 个条件才能算是 “无用的类” :
该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
加载该类的 ClassLoader 已经被回收。
该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

虚拟机可以对满足上述 3 个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样不使用了就会必然被回收

  • 34
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向着百万年薪努力的小赵

感谢大佬,大佬步步高升

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值