文章目录
- 1JVM参数
- 1.1 标准参数
- 1.2 -X 参数(非标准参数)
- 1.3 -XX 参数(非Stable参数)
- 1.3.1性能参数
- 1.3.2行为参数
- 1.3.3调试参数
- 1.4其他参数(一定要背下来)
- 2设置参数的方式
- 3 五大常用命令(一定要背下来)
- 3.1 JPS
- 3.2 jinfo
- 3.3 jstat
- 3.4 jstack 堆栈信息
- 3.5jmap
- 4调优常用工具
- 4.1jconsole
- 4.2jvisualvm
- 4.3 MAT
- 4.4使用MAT
- 5调优实战分析
- 5.1生产环境事故
- 5.2程序监控调优
- 5.3GC的次数频繁怎么办?
- 5.4几个面试问题
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[:...|:]
-enableassertions[:...|:]
按指定的粒度启用断言
-da[:...|:]
-disableassertions[:...|:]
禁用具有指定粒度的断言
-esa | -enablesystemassertions
启用系统断言
-dsa | -disablesystemassertions
禁用系统断言
-agentlib:[=<选项>]
加载本机代理库 , 例如 -agentlib:hprof
另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:[=<选项>]
按完整路径名加载本机代理库
-javaagent:[=<选项>]
加载 Java 编程语言代理, 请参阅 java.lang.instrument
-splash:
使用指定的图像显示启动屏幕
有关详细信息, 请参阅 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: 将 GC 状态记录在文件中(带时间戳) -Xbatch 禁用后台编译 -Xms 设置初始 Java 堆大小 -Xmx 设置最大 Java 堆大小 -Xss 设置 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=70 | GC后java堆中空闲量占的最大比例,大于该值,则堆内存会减少 |
-XX:MinHeapFreeRatio=40 | GC后java堆中空闲量占的最小比例,小于该值,则堆内存会增加 |
-XX:NewRatio=2 | 新生代内存容量与老生代内存容量的比例 |
-XX:ReservedCodeCacheSize= 32m | 保留代码占用的内存容量 |
-XX:ThreadStackSize=512 | 设置线程栈大小,若为0则使用系统默认值 |
-XX:LargePageSizeInBytes=4m | 设置用于Java堆的大页面尺寸 |
-XX:PretenureSizeThreshold= size | 大于该值的对象直接晋升入老年代(这种对象少用为好) |
-XX:SurvivorRatio=8 | Eden区域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设置参数的方式
- 开发工具 IDEA 、Eclipse 在run configuration 里设置VM option 运行jar包, java -XX:+UseG1GC xxx.jar
- 线上环境 web容器:Tomcat, startup.sh -> catalina.sh(卡特琳娜) 里设置JVM 参数 jsp + jinfo 查看某个java进程的参数,然后再调整设置
- 真实调优 java -XX:+UseG1GC xxx.jar
3 五大常用命令(一定要背下来)
3.1 JPS
查看java进程id
查看当前系统上,正在运行的java 进程 id列表和运行的类全限定名
3.2 jinfo
查看参数
- 实时查看某个进程id的jvm 参数
- 查看某个进程id的所有jvm参数
- 修改我们可以 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 | 用于指定输出多少次记录,缺省则会一直打印 |
举几个例子:
- 查看类装载信息
jstat -class PID 1000 10 查看某个java进程的类装载信息,每1000毫秒输出一 次,共输出10次
- 查看垃圾收集信息 jstat -gc PID 1000 10
参数 | 解析 |
S0C | Survivor0(幸存者0区)大小(KB) |
S1C | Survivor1(幸存者1区)大小(KB) |
S0U | Survivor0(幸存者0区)已使用大小(KB) |
S1C | Survivor1(幸存者1区)以使用大小(KB) |
EC | Eeden(伊甸区)大小(KB) |
EU | Eden(伊甸区)已使用大小(KB) |
OC | 老年代大小(KB) |
OU | 老年代已使用大小 (KB) |
OC | 老年代大小(KB) |
OU | 老年代已使用大小(KB) |
PC | Perm永久代大小(KB) |
PU | Perm永久代已使用大小(KB) |
YGC | 新生代GC个数 |
YGCT | 新生代GC的耗时(秒 |
FGC | Full GC次数 |
FGCT | Full GC耗时(秒) |
GCT | GC总耗时(秒) |
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相关记录
解决思路:
- 业务日志 没有错误
- JVM 错误日志 hs_error_pid.log
可以通过设置以下这个参数,来指定错误日志路径 -XX:ErrorFile=./
通过分析我们的 jvm 错误日志定位问题,然后解决。
5.2程序监控调优
前提:java 应用程序必然是正常运行的。.
目的:减少GC 频率,减少Full GC
发现现象才去解决?比如说 CPU 飙升、内存飙升
- 打印dump文件分析堆内存
- 打印GC日志,分析日志文件
-Xms30m -Xmx30m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap1.hprof -XX:+PrintGCDetails -Xloggc:gc.log
- 定位问题
- 调节参数
- 观察结果
- 重复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 个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样不使用了就会必然被回收