JVM系列之性能调优参考手册(实践篇)
系列博客专栏:
1、前言介绍
在前面章节的学习,我们对JVM的体系架构等等有了比较详细的了解,所以可以对这些理论进行实践,当然只是通过一些example,实践的生产环境要复杂得多,所以本博客只能作为学习参考资料。一般来说,JVM内部是经过很多的实践和优化的,所以一般调休是先通过java提供的工具进行性能问题排查,找出影响性能的代码,然后迫不得已才可以考虑调整JVM参数,进行JVM参数调优。
2、标准参数
标准参数以-开头,所有jvm都实现了该参数的功能
-
-help 查看java命令帮助信息 -
-server -client 两个参数用于设置虚拟机使用何种运行模式,client模式启动比较快,但运行时性能和内存管理效率不如server模式。相反,server模式启动比client慢,但是运行时性能和内存管理效率比较高。64bit版本默认设置-server -
-version 查看java版本, -cp -classpath 指定classpath路径 -
-jar 指定运行一个jar包,jar包中manifest文件中必须指定Main-class -
-verbose 打印jvm载入类的相关信息 -
-verbose:gc 打印gc信息 -
-verbose:jni 打印native方法调用信息 -
等等,…
3、非标准参数
非标准参数以-X开头,给jvm实现这些参数的功能,但是不是所有的jvm都有这些功能。同时在不同JDK版本也有可能变动,所以说这些参数是非标准参数
- -Xint
解释执行 - -Xcomp
编译执行,第1次使用就编译成本地代码 - -Xmixed
混合模式,jvm自己决定
[www@localhost ~]$ java -Xint -version
java version "11.0.9" 2020-10-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.9+7-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.9+7-LTS, interpreted mode)
[www@localhost ~]$ java -Xcomp -version
java version "11.0.9" 2020-10-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.9+7-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.9+7-LTS, compiled mode)
[www@localhost ~]$ java -Xmixed -version
java version "11.0.9" 2020-10-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.9+7-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.9+7-LTS, mixed mode)
[www@localhost ~]$
-
-Xms eg:-Xms1g 指定jvm初始内存为1g -
-Xmx eg:-Xmx1g 指定jvm最大可用内存为1g -
-Xmn eg:-Xmn1g 指定年轻代大小为1g,增加年轻代容量会缩小年老代容量 -
-Xss -Xss1m ,设置线程堆栈大小,默认1m -
-Xloggc eg:-Xloggc:gc.log ,将gc日志记录到gc.log文件中 -
-Xprof 跟踪正运行的程序,并将跟踪数据在标准输出输出 -
等等,…
4、不稳定参数
no Stable,不稳定参数以 -XX 开头,使用最多的参数类型,非标准化参数,相对不稳定,主要用于JVM调优和Debug
- Boolean类型
格式:-XX[+/-]<name> ,+ 表示启用,- 表示禁用 例子:-XX:+UseConcMarkSweepGC ,表示启用CMS类型的垃圾回收器 - 非Boolean类型
格式:-XX<name>=<value> 表示name 属性的值是value 例子:-XX:MaxGCPauseMillis=500
- -XX:PermSize
非堆,也可以说是方法区,内存初始大小 - -XX:MaxPermSize
方法区,最大内存大小 - -XX:-UseSerialGC
使用串行GC - -XX:-UseParallelGC
使用并行GC - -XX:-UseConcMarkSweepGC
对老年代使用CMS(Concurrent Mark And Sweep)GC
参数 | 含义 | 说明 |
---|
-XX:CICompilerCount | 最大并行编译数 | 如果设置大于1,会提高编译速度,但是同样影响系统稳定性,会增加jvm奔溃的可能 | -XX:InitialHeapSize=100M | 初始化堆大小 | 简写-Xms100M | -XX:MaxHeapSize=100M | 最大堆大小 | 简写-Xms100M | -XX:NewSize=20M | 设置年轻代的大小 | | -XX:OldSize=50M | 设置老年代的大小 | | -XX:MetaspaceSize=50M | 设置方法区的大小 | | -XX:MaxMetaspaceSize=50M | 方法区最大大小 | | -XX:+UseParallelGC | 使用UseParallelGC | 并行收集器,作用于新生代,吞吐量优先 | -XX:+UseParallelOldGC | 使用UseParallelOldGC | 并行收集器,作用于老年代,吞吐量优先 | -XX:+UseConcMarkSweepGC | 使用CMS | 作用于老年代,停顿时间优先 | -XX:+UseG1GC | 使用G1GC | 作用于新生代,老年代,停顿时间优先 | -XX:NewRatio | 新老生代的比值 | 比如-XX:Ratio=4,表示新生代:老年代=1:4,也就是新生代占整个堆内存的1/5 | -XX:SurvivorRatio | 两个S区和Eden区的比值 | 比如-XX:SurvivorRatio=8,也就是(S0+S1):Eden=2:8,也就是一个S占整个新生代的1/10 | -XX:+HeapDumpOnOutOfMemoryError | 启动堆内存溢出打印 | 当JVM堆内存发生溢出时,也就是OOM,自动生成dump文件 | -XX:HeapDumpPath=heap.hprof | 指定堆内存溢出打印目录 | 表示在当前目录生成一个heap.hprof文件 | -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:gc.log | 打印GC日志,保存到gc.log | | -Xss128k | 设置每个线程的堆栈大小 | 经验值是3000-5000最佳 | -XX:MaxTenuringThreshold=15 | 提升年老代的最大临界值 | 默认值为 15 | -XX:InitiatingHeapOccupancyPercent | 启动并发GC周期时堆内存使用占比 | 默认值为 45. | -XX:G1HeapWastePercent | 允许的浪费堆空间的占比 | 默认是10%,如果并发标记可回收的空间小于10%,则不会触发MixedGC | -XX:MaxGCPauseMillis=200M | G1最大停顿时间 | 暂停时间不能太小,太小的话就会导致出现G1跟不上垃圾产生的速度。从而造成full gc。 | -XX:ConcGCThreads=n | 并发垃圾收集器使用的线程数量 | 默认值随JVM运行的平台不同而不同 | -XX:G1MixedGCLiveThresholdPercent=65 | 混合垃圾回收周期中要包括的旧区域设置占用率阈值 | 默占用率为 65% | -XX:G1MixedGCCountTarget=8 | 设置标记周期完成后,对存活数据上限为G1MixedGCLIveThresholdPercent的旧区域执行混合垃圾回收的目标次数 | 默认8次混合垃圾回收,混合回收的目标是要控制在此目标次数以内 | -XX:G1OldCSetRegionThresholdPercent=1 | 描述Mixed GC时,Old Region被加入到CSet中 | 默认占用率为 65% | -XX:LargePageSizeInBytes=4m | 设置用于Java堆的大页面尺寸 | | -XX:MaxHeapFreeRatio=70 | GC后java堆中空闲量占的最大比例 | | -XX:MaxNewSize=size | 新生成对象能占用内存的最大值 | | -XX:MaxPermSize=64m | 老生代对象能占用内存的最大值 | | -XX:MinHeapFreeRatio=40 | GC后java堆中空闲量占的最小比例 | | -XX:ReservedCodeCacheSize=32m | 保留代码占用的内存容量 | | -XX:ThreadStackSize=512 | 设置线程栈大小,若为0则使用系统默认值 | | -XX:+UseLargePages | 使用大页面内存 | | -XX:-CITime | 打印消耗在JIT编译的时间 | | -XX:ErrorFile=./hs_err_pid.log | 保存错误日志或者数据到文件中 | | -XX:-ExtendedDTraceProbes | 开启solaris特有的dtrace探针 | | -XX:OnError=”;“ | 出现致命ERROR之后运行自定义命令 | | -XX:OnOutOfMemoryError=”;“ | 当首次遭遇OOM时执行自定义命令 | | -XX:-PrintClassHistogram | 遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同 | | -XX:-PrintConcurrentLocks | 遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同 | | -XX:-PrintCommandLineFlags | 打印在命令行中出现过的标记 | | -XX:-PrintCompilation | 当一个方法被编译时打印相关信息 | | -XX:-TraceClassLoading | 跟踪类的加载信息 | | -XX:-TraceClassLoadingPreorder | 跟踪被引用到的所有类的加载信息 | | -XX:-TraceClassResolution | 跟踪常量池 | | -XX:-TraceClassUnloading | 跟踪类的卸载信息 | | -XX:-TraceLoaderConstraints | 跟踪类加载器约束的相关信息 | |
[www@localhost ~]$ java -XX:+PrintFlagsFinal -version > log.txt
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
5、常用命令
jps命令用于查看java进程
The jps command lists the instrumented Java HotSpot VMs on the target system. The command is limited to reporting information on JVMs for which it has the access permissions.
[www@localhost ~]$ jps
4352
8480 Jps
1736 RemoteMavenServer
3144 SmartGit
7612 Bootstrap
[www@localhost ~]$ jps -l
3024 sun.tools.jps.Jps
4352
1736 org.jetbrains.idea.maven.server.RemoteMavenServer
3144 SmartGit
7612 org.apache.catalina.startup.Bootstrap
- jinfo
jinfo命令用于实时查看和调整jvm配置参数
语法:
jinfo -flag name PID // 查看某个java进程的name属性的值jinfo -flag [+/-] <name> PID // 启用禁用JVM属性jinfo -flag <name>=<value> PID // 设置JVM参数(name)的值(value)
查看进程4352的MaxHeapSize属性
[www@localhost ~]$ jinfo -flag MaxHeapSize 4352
-XX:MaxHeapSize=786432000
jinfo修改MaxHeapSize值
jinfo -flag MaxHeapSize=786432000 4352
jinfo -flag PID 查看曾经赋过值的一些参数
[www@localhost ~]$ jinfo -flag 7612
Usage:
jinfo [option] <pid>
(to connect to running process)
jinfo [option] <executable <core>
(to connect to a core file)
jinfo [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)
where <option> is one of:
-flag <name> to print the value of the named VM flag
-flag [+|-]<name> to enable or disable the named VM flag
-flag <name>=<value> to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties
<no option> to print both of the above
-h | -help to print this help message
The jstat command displays performance statistics for an instrumented Java HotSpot VM. The target JVM is identified by its virtual machine identifier, or vmid option.
查看类装载信息,例子,查看某个java进程的类装载信息,每1000毫秒输出一次,共输出10次
[www@localhost ~]$ jstat -class 3760 1000 10
Loaded Bytes Unloaded Bytes Time
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
13080 26809.1 250 390.1 29.27
查看垃圾收集信息
[www@localhost ~]$ jstat -gc 3760 1000 10
S0C S1C S0U S1U EC EU OC OU MC MU
CCSC CCSU YGC YGCT FGC FGCT GCT
24576.0 48640.0 767.1 0.0 528896.0 492086.2 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 492086.2 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 492086.2 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 492086.2 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 492086.2 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 492086.2 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 492086.2 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 502965.7 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 502965.7 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
24576.0 48640.0 767.1 0.0 528896.0 502965.7 214528.0 109639.1 89856.0 87
215.8 9472.0 8955.5 28 0.965 4 0.810 1.775
The jstack command prints Java stack traces of Java threads for a specified Java process, core file, or remote debug server.
语法:jstack PID
两个锁互相持有,造成死锁案例:
public class LockDemo
{
public static void main(String[] args)
{
LockThread d1=new LockThread(true);
LockThread d2=new LockThread(false);
Thread t1=new Thread(d1);
Thread t2=new Thread(d2);
t1.start();
t2.start();
}
}
class MyLock{
public static Object obj1=new Object();
public static Object obj2=new Object();
}
class LockThread implements Runnable{
private boolean flag;
LockThread(boolean flag){
this.flag=flag;
}
public void run() {
if(flag) {
while(true) {
synchronized(MyLock.obj1) {
System.out.println(Thread.currentThread().getName()+"获得obj1锁");
synchronized(MyLock.obj2) {
System.out.println(Thread.currentThread().getName()+"获得obj2锁");
}
}
}
} else {
while(true){
synchronized(MyLock.obj2) {
System.out.println(Thread.currentThread().getName()+"获得obj2锁");
synchronized(MyLock.obj1) {
System.out.println(Thread.currentThread().getName()+"获得obj1锁");
}
}
}
}
}
}
jstack进行分析,
[www@localhost ~]$ jps -l
2560
2624 SmartGit
3760 org.apache.catalina.startup.Bootstrap
5316 org.jetbrains.idea.maven.server.RemoteMavenServer
7400 sun.tools.jps.Jps
8104 LockDemo
1116 org.jetbrains.jps.cmdline.Launcher
[www@localhost ~]$ jstack 8104
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 PID
当然可以设置发生堆内存溢出的时候,能自动dump出该文件,加上启动参数:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof
写个Threadlocal例子:
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = {"/api"})
public class ThreadLocalHeapController {
@GetMapping(value = "/testHeap")
public ResponseEntity<?> testHeap() {
ThreadLocal<Byte[]> threadLocal = new ThreadLocal<Byte[]>();
try {
threadLocal.set(new Byte[1024 * 1024]);
return ResponseEntity.ok("success");
}catch (Exception e) {
return ResponseEntity.badRequest().build();
} finally {
}
}
}
设置发生堆内存溢出的时候,能自动dump出日志文件
java -jar -Xms1000M -Xmx1000M -XX:+HeapDumpOnOutOfMemoryError -
XX:HeapDumpPath=jvm.hprof jvm-exception-example-0.0.1-SNAPSHOT.jar
在linux系统进行AB压测:10000次请求,并发100
[www@localhost ~]$ ab -n 10000 -c 100 http://127.0.0.1:8080/api/testHeap
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software:
Server Hostname: 127.0.0.1
Server Port: 8080
Document Path: /api/testHeap
Document Length: 7 bytes
Concurrency Level: 100
Time taken for tests: 10.504 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 1390000 bytes
HTML transferred: 70000 bytes
Requests per second: 952.01 [
Time per request: 105.041 [ms] (mean)
Time per request: 1.050 [ms] (mean, across all concurrent requests)
Transfer rate: 129.23 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 0.7 0 10
Processing: 7 104 43.1 100 1223
Waiting: 7 100 38.8 99 1213
Total: 7 104 43.1 101 1224
WARNING: The median and mean for the initial connection time are not within a normal deviation
These results are probably not that reliable.
Percentage of the requests served within a certain time (ms)
50% 101
66% 105
75% 108
80% 110
90% 119
95% 144
98% 185
99% 219
100% 1224 (longest request)
jmap -heap PID再打印一下堆信息,可以看到并发的情况,内存溢出
当然拿到堆异常日志后,可以使用GCViewer等等根据进行性能分析,本博客只是以一个简单的例子进行分析,生产环境特别复杂,需要多年的经验和很好的耐心
|