点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。
文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。
具体参数如下:
F:\Iwebapp\demo-test>jmap -heap 10864
Attaching to process ID 10864, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.65-b01
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0 //空余堆内存最小百分比,HeapFreeRatio=空闲堆内存的百分比=现有空闲堆内存/总共对内存*100,当MinHeapFreeRatio
实战源码:以demo-test工程为例,用gcviewner和jdk内置的监控jvm命令来做jvm调优
package com.example.demo;
import com.example.util.ThreadTest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoTestApplication {
public static void main(String[] args) {
SpringApplication.run(DemoTestApplication.class, args);
ThreadTest.testJVM();
}
}
public class ThreadTest {
public static void main(String[] args) {
testJVM();
}
public static void testJVM(){
//匿名内部类重写Runnable的run方法可以写成箭头函数:()->{run方法的内容}
//1000ms后每50ms执行创建1个线程,每个线程150*512*1024byte=150*512*1024B=150*512k=150*0.5M=75M,1s内最多1000/50=20个线程,则1s内最大占用内存=75*20=150M
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(()->{
new Thread(()->{
for(int i=1;i<=150;i++){
byte[] b=new byte[1024*512];//0.5M
}
System.out.println(Thread.currentThread().getName()+"已分配512k内存...");
}).start();
},1000,50,TimeUnit.MILLISECONDS);
}
在target目录下【java -jar -Xloggc:gc.log -Xmx35m -Xms35m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps demo-test.jar】启动jar包或者直接在idea中添加【-Xloggc:gc.log -Xmx35m -Xms35m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps】启动springboot启动类,以下用gcviewner监控JVM :
gcviwner是一款可以监控GC日志的工具,前提是要拿到gc日志,gcviwner用法可参考【https://github.com/chewiebug/GCViewer】 ,命令 【java -jar gcviewer-1.37-SNAPSHOT.jar】启动gcviwner,并导入gc.log日志,如下,
上中下三张图,由上图可知吞吐量为74.26%,一般可以达到90%以上,红线是堆的实时总内存,蓝线是堆的实时已使用内存,灰色为young gc,黑色为full gc,可知灰色的线太密集=young gc频繁,黑色的线也是太密集=full gc频繁;full gc总数为296,一般可以把full gc降到个位数;
由中图可知最大停顿时间比较大,达到了892ms,一般可调优到几十毫秒级别;
有下图可看到young gc和full gc的情况,full gc次数296,比较频繁;同时元空间metadata区域过小,可以适当调大
由上,把metadata调为64M,执行【java -jar -XX:MetaspaceSize=64m -Xloggc:gc.log -Xmx35m -Xms35m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps demo-test.jar】重新启动jar包:
可知full gc次数还是比较多、最大停顿时间也比较长、吞吐量也低,尝试着增大’最大堆内存’,执行【java -jar -XX:MetaspaceSize=64m -Xloggc:gc.log -Xmx100m -Xms100m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps demo-test.jar】重新启动jar包:
可知full gc次数变少了(黑线少了,0次)、最大停顿时间也短了(94.65ms,到了十几毫秒级别)、吞吐量也高了(93.83%)
至此,调优基本满足上面的【减少full gc、降低gc停顿时间、提高吞吐量】的要求。
下面是jdk内置的jvm监控命令
jstat命令用于监视虚拟机的运行状态,命令格式【jstat -参数命令 进程号 间隔毫秒数 总输出次数】,主要参数项:
//每1000ms统计一次demo-test-0.0.1.jar的gc信息
jstat -gc $(jcmd | grep "demo-test-0.0.1.jar" | awk '{print $1}') 1000
S0C、S1C、S0U、S1U:C是总量,U是使用量,代表S0(survivorFrom区)和S1(survivorTo区)的总量与使用量
EC、EU:Eden区总量与使用量
OC、OU:Old区总量与使用量
MC、MU: Metaspace区(元空间)总量与使用量
YGC、YGCT:young gc的次数与时间
FGC、FGCT:full gc的次数与时间<
GCT:总的GC时间
//每1000ms统计一次进程ID为10492的gc信息,共统计10次数结束统计
jstat -gc 10492 10
jps可以查看正在运行的java进程,命令格式【jsp 参数】,主要参数项:
【jsp -l】查看具体的包名
可以查看启动jar包时未显式指定的系统默认值,以及动态修改这些默认值,命令格式【jinfo -flag 默认的参数 进程id】,查看【年轻代:老年代】的内存比例:
jmap查看java内存信息,命令格式【jmap -参数 进程id】,参数项:
实例如上:【jmap -heap 10864】查看进程号为10864的进程的堆使用情况
//查看进程的堆栈及锁的信息
jstack -l 10220
参数 | 说明 |
---|---|
-XX:+UseParallelGC | 新生代使用并行回收收集器 |
-XX:+Use ParalleloldGC | 老年代使用并行回收收集器 |
-XX:ParallelGCThreads | 设置用于垃圾回收的线程数 |
-XX:+UseAdaptiveSizePolicy | 打开自适应GC策略 |
OK,如果文章哪里有错误或不足,欢迎各位留言。
创作不易,各位的「三连」是二少创作的最大动力!我们下期见!