jvm性能优化涉及到两个很重要的概念:吞吐量和响应时间。jvm调优主要是针对他们进行调整优化,达到一个理想的目标,根据业务确定目标是吞吐量优先还是响应时间优先。
调优方法论
监控JVM性能
压测基准指标
调整JVM参数
二次压测分析
其他优化方式
优化代码
使用并发编程
使用缓存
避免IO阻塞
分布式+集群技术
/**
* @author lixiang
* @date 2023/5/8 21:44
*/
@Slf4j
@RestController
@RequestMapping("/spring-test")
public class SpringTestController {
@RequestMapping("query")
public Map<String, Object> query() throws InterruptedException {
int num = (int) (Math.random() * 100) + 1;
//申请5MB内存
Byte[] bytes = new Byte[5 * 1024 * 1024];
List<Product> productList = new ArrayList<>();
for (int i = 0; i < num; i++) {
Product product = new Product();
product.setPrice((int) Math.random() * 100);
product.setTitle("商品编号" + i);
productList.add(product);
}
Thread.sleep(5);
Map<String, Object> map = new HashMap<>(16);
map.put("data", productList);
return map;
}
}
-Xms1g # 配置初始堆内存1G
-Xmx1g # 配置最大堆内存1G
-XX:+UseG1GC # 使用G1回收器
-XX:MaxGCPauseMillis=200 # 设置最大停顿时间200ms
-XX:G1HeapRegionSize=32M # 设置G1每个region块大小为32M
-XX:ActiveProcessorCount=8 # 设置JVM使用的CPU核数限制为8
-XX:+HeapDumpOnOutOfMemoryError # 当JVM发生OOM时,自动生成DUMP文件
-XX:HeapDumpPath=heapdump.hprof # DUMP文件路径
-XX:+PrintCommandLineFlags # 监控开启
-Xlog:gc=info:file=portal_gc.log:utctime,level,tags:filecount=50,filesize=100M
# Xlog:指定日志输出方式为日志文件。
# gc*:指定日志输出类型为GC相关的日志。
# info:指定输出日志的级别为info级别。
# file=portal_gc.log:指定日志输出的文件名为portal_gc.log。
# utctime:指定日志输出的时间戳使用UTC时间。
# level,tags:指定日志输出的格式包含级别和标签信息。
# filecount=50:指定最多保存50个日志文件。
# filesize=100M:指定每个日志文件的大小为100MB。
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms1g -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &
当我们设置堆内存为1G的时候,整体的吞吐量为40%以上,这已经很低了,期间Young GC发生了7451次,Full GC发生了142次
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms2g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &
我们将堆内存设置为2G的时候,相比于1G的吞吐量提升到70%以上,并且Young GC次数为752,Full GC次数为6次,相比1G提升了一倍。
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &
当把堆内存设置为4G的时候,整体的吞吐量提升到76%,Young GC发生了504,一次Full GC都没有发生。
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms6g -Xmx6g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &
当把堆内存设置为6G的时候,整体吞吐量到达87%,Yong GC发生了196次,Full GC发生了0次。
总结:通过对堆内存的调整,发现4G是投入产出比最高的参数配置,所以当前配置可以采用4G的堆内存。
通过上面配置堆内存我们得出4G是当前机器和应用配置的最佳堆内存,这里我们不改变堆内存的大小,采用4G的堆内存,改变垃圾收集器,看看对接口吞吐量的影响。
这里我们采用ParallelGC,目前G1垃圾器在对于并发量大的应用来说,已经是最优的选择啦,我们这里用ParallelGC主要做一个对比。
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms4g -Xmx4g -XX:+UseParallelGC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &