springboot-jvm调优

JVM调优是做什么的?为什么要调优?下面让我们一起实战一下尝试调优。

目录

一、jvm调优的目的(理论)

二、jvm调优常用的工具介绍

三、java项目vm参数配置

四、调优实战

1、JPS

2、jmap

3、jconsole

5、jvisualvm

5.1 增加java启动参数,增加OOM时的触发记录dump功能来排查异常挂机。

5.2 jvisualvm加载dump文件分析。

5.3 jvisualvm抽样分析和快照分析。

6、jinfo

7、jmc

五、其它工具

jstack

jcmd

jhat



一、jvm调优的目的(理论)

1. 提高性能:通过调整JVM参数、垃圾回收策略、内存分配等,可以减少应用程序的响应时间,提高吞吐量和并发能力,从而提升应用程序的整体性能。

2. 降低内存占用:通过调整堆内存大小、垃圾回收机制等,可以降低应用程序的内存占用,减少内存泄漏和频繁的垃圾回收,提高系统的稳定性和可伸缩性。

3. 优化垃圾回收:选择合适的垃圾回收算法和参数配置,可以减少垃圾回收的停顿时间,提高系统的响应性能。

4. 资源利用率优化:通过合理配置线程池、IO操作、数据库连接等资源的使用方式,提高资源利用率,避免资源竞争和瓶颈问题。

5. 诊断和排查问题:通过JVM调优工具和性能分析工具,可以定位和解决应用程序的性能问题、内存泄漏、死锁等常见的运行时问题。

平常主要是两个方面:服务器资源不够时,各java应用进行资源分配。高内存占用时问题排查。

二、jvm调优常用的工具介绍

JVM有很多图形化的工具,大名鼎鼎的有EclipseMemoryAnalyzer(MAT),下面我介绍一下jdk中自带的几个工具。

首先你的电脑中需要正确安装了JDK,然后配置了环境变量:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

springboot-jvm调优_第1张图片

然后,在CMD窗口,输入jps -help看是否正确:

springboot-jvm调优_第2张图片

如果正确,则下面几个工具都应该是可以直接使用了。

springboot-jvm调优_第3张图片

JDK自带的JVM调优工具:

  • jhat
  • jinfo
  • jmap
  • jmc
  • jps
  • jstack
  • jstat
  • jstatd
  • jvisualvm
  • jconsole

(下面就不一一介绍,仅介绍我此次排查用到的工具。)

三、java项目vm参数配置

当我们运行一个java项目时,我们除了直接运行以外,还可以加一个启动参数,对应IDEA中是vm参数。

比如:java -Xms50m -Xmx50m -jar bill-base-1.0.jar

这代表啥意思呢,让我们一起看一下java命令的说明:

springboot-jvm调优_第4张图片

那现在我们应该明白了, -X表示非标准选项。ms表示选项名称,50m是值。

比如说常用到的设置:

-Duser.timezone=GMT+08 //设置用户的失去为东八区 
-Dfile.encoding=UTF-8 //设置默认的文件编码为UTF-8
-Djava.test.skip=true // 跳过单元测试

JVM 的内存设置是最重要的参数设置,也是GC 分析和调优的重点。

​ JVM 总内存 = 堆 + 栈 + 非堆 + 堆外内存。

相关参数:

-Xmx :指定最大堆内存。如-Xmx4g 这只是限制了 Heap部分的最大值为4g。这个内存不包括栈内存,也不包括堆外使用的内存。
-Xms :指定堆内存空间的初始化大小,如-Xms4g 。指定的内存大小,并不是操作系统实际分配的初始值,而是 GC 先规划好,用到才分配。专用服务器上需要保持 -Xmx 和 -Xms 一致,否则应用刚启动更可能就有好几个FullGC。当两者配置不一致时,堆内存扩容可能会导致性能波动。
-Xmn :等价于 -XX:NewSize,使用G1垃圾回收器不应该设置该选线,官方建议设置为 -Xmx 的 1/2 ~ 1/4。
-XX : MaxPermSize=size, 这是jdk1.7之前使用的。Java8 默认允许的Meta空间无限大,此参数无效。
XX : MaxDDirectMemorySize=size, 系统可以使用的最大堆外内存,这个参数跟-Dsun.nio.MaxDirectMemorySize 效果相同。
-Xss :设置每个线程栈的字节数。例如 -Xss1m 指定线程栈1MB,与-XX:ThreadStackSize=1m等价

四、调优实战

我们上面说了那么参数,大部分新和都记不住的。那当我们启动了一个java应用以后,如何知道我这个应用当前的内存配置参数是多少呢?

仍以上面启动的命令为例:java -Xms50m -Xmx50m -jar bill-base-1.0.jar

1、JPS

首先通过jps快速获取java应用的pid(进程ID),通过名称确认我们要查找的java是哪一个pid。

jps -q //不输出类名,jar包名和传入main方法的参数(只显示进程号)
jps -m //输出传入main方法的参数
jps -l //输出mian类和jar的全限名
jps -v // 输出传入JVM的参数

我们可以任意思组合使用,比如-lm

2、jmap

通过jps工具,我们可以获取知道我们的应用pid是36936。然后我们就可以用jmap获来信息了。

springboot-jvm调优_第5张图片

springboot-jvm调优_第6张图片

jmap完整的命令如下:

 jmap -permstat pid  //打印进程的类加载器和类加载器加载的持久代对象信息
 jmap -heap pid  //查看进程堆内存使用情况,包括使用的GC算法、堆配置参数和各代中堆内存使用
 jmap -histo[:live] pid //查看堆内存的对象数目,大小统计直方图,如果带上live则只统计活对象
 jmap -dump:format=b,file=/usr/local/logs/gc/dump.hprof pid //以二进制输出档当前内存的堆情况,然后可以导入 MAT 等工具进行

通过上面的命令,我们可看到, MaxHeapSize=50m,和我启动时 -Xmn50m是一致的,说明我们的配置生效了。

3、jconsole

通过jconsole,打开图形化窗口,用来查看java应用的更多信息。

springboot-jvm调优_第7张图片

当我们打开jconsole以后,它会开始监听这个java应用的一些信息,我们稍等一会就能看到连续的曲线了。

springboot-jvm调优_第8张图片

springboot-jvm调优_第9张图片

springboot-jvm调优_第10张图片

springboot-jvm调优_第11张图片

这里面会是示这个应用运行的时长,类加载的情况,内存的情况等。

5、jvisualvm

CMD命令中输入jvisualvm命令,会打开图形化界面。

springboot-jvm调优_第12张图片

初看上去,这个工具和jconsole很像,都是起监作用。但这个工具可是今天我要调优的主要工具。

当我们应用出现问题时,一般是两种现象,一个是直接已经超出内存OutOfMemoryError。另一种是高内存占用但还未超出。

那么,我们对于这两种问题排查方式也略有区别。对于OutOfMemoryError,有可能已经导致java应用挂掉。所以我们进行配置,当出现这种情况时记录到dump文件,已便离线分析(比如服务器下载到本地)

5.1 增加java启动参数,增加OOM时的触发记录dump功能来排查异常挂机。

为了演示,我写了一个接口如下:

    @GetMapping("/{id}/set")
    public String get3(@PathVariable String id) {
        // @PathVariable定义路径参数,并在Mapping中{id}定义参数位置
        System.out.println(Integer.MAX_VALUE);

        List list = new ArrayList<>();
        for (int i =0;i<2000000;i++){
            SysUser sysUser = new SysUser();
            sysUser.setId((long) i);
            sysUser.setNickName( String.valueOf(MyStringUtil.getRandomChar()) );
            list.add(sysUser);
        }
        System.out.println("list end");
        return "path args " + id + "stringBuilderA.len:" +list.size();
    }

上面的接口很简单,就是不停的循环去插入一个用户类到一个list中。我们重新编译成jar。

那么,我们就可以在java启动时增加参数来实现记录dump的功能:

java -Xms50m -Xmx50m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/dump008/ -jar bill-base-1.0.jar
// 为了更方便查找问题,我们调小了初始的内存大小和最大值

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=d:/dump008

这样,当我们代码中出现了OOM情况时,会自动记录到Dump文件。

当我们去调用这个接口时,返回一个OOM错误:

5.2 jvisualvm加载dump文件分析。

当出现OOM时,我们就可以获取Dump文件来进行分析了。(先从服务器下载到本地)

先在CMD窗口启动jvisualvm,在图形化界面中选择菜单 文件 - 载入,加载对应的dump文件。

springboot-jvm调优_第13张图片

工具已经自动帮我们分析了出现OOM的入口了,点击链接一步步查看即可。

springboot-jvm调优_第14张图片

springboot-jvm调优_第15张图片

我们还可以通过类和实例查看具体的内容

springboot-jvm调优_第16张图片

我们通过实例数可以看到具体的变量及值的情况:

springboot-jvm调优_第17张图片

到这里,我们基本上已经定位到就是变量SysUser过高造成的。

5.3 jvisualvm抽样分析和快照分析。

java内存高时,另一种情况就是未OOM,但有大对象占用,需要实时分析。那么我们可以利用jvisualvm的抽样器进行分析。

为便于演示,下面我们调整vm参数增加内存到500m,重新启动:

java -Xms500m -Xmx500m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/dump008/ -jar bill-base-1.0.jar
// 为了更方便查找问题,我们调小了初始的内存大小和最大值

当我们再次访问接口,我们就会发现并没有出现OOM,只不过CPU\内存有一些小波动:

springboot-jvm调优_第18张图片

springboot-jvm调优_第19张图片

从内存堆可以看出来,有一段时间续持占用300M左右。

那么我们也可以同样借助抽样器来分析。

启动内存抽样器:

springboot-jvm调优_第20张图片

再次访问接口后观察变化:

springboot-jvm调优_第21张图片

当我们抓取到我们需要的现象以后,我们就可以另存为dump文件,参照离线dump的方式法进行分析。

保存为堆Dump文件或应用程快照。

springboot-jvm调优_第22张图片

可以将这个dump文件保存到本地文件,这样可以像离线分析一下后续进一步分析或处理。

springboot-jvm调优_第23张图片

6、jinfo

jinfo -flags 71228

当一个已经在运行的java应用我们想知道它的启动参数时,就可以通过上面来获取(

 作用和 jmap -heap 71228差不多,但多了一些VM选项)

springboot-jvm调优_第24张图片

7、jmc

这也是一个可视化工具,都是中文,就不解说了

springboot-jvm调优_第25张图片 

五、其它工具

jstack

jstack 是用来打印当前虚拟机的线程快照(线程快照也叫 Thread Dump 或者 javacore文件)

jcmd

看当前服务器内的全部的java应用,将诊断命令请求发送到正在运行的Java虚拟机

jhat

用来分析jmap生成的dump文件

好像网友都说不常用,就不研究了。知道就行,有需要时再百度吧。

你可能感兴趣的:(springboot,spring,boot,jvm,后端)