"简单"的jvm调优

3,359 阅读4分钟

    作为一名励志成为"神奇宝贝大师"的男人,怎么能连JVM都不懂呢,不然你可能会像智爷那样,一辈子拿不到冠军了。
    java能在多平台运行的基础就是java虚拟机了,这边我们不谈论它的内存区域,毕竟jdk7的方法区和jdk8元空间还是有区别的。

jvm参数

//常见参数
-Xms1024m 初始堆大小 
-Xmx1024m 最大堆大小  一般将xms和xmx设置为相同大小,防止堆扩展,影响性能。
-XX:NewSize=n:设置年轻代大小 
-XX:NewRatio=n:设置年轻代和年老代的比值.如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4 
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值.注意Survivor区有两个.如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5 
-XX:MaxPermSize=n:设置持久代大小
-XX:+HeapDumpOnOutOfMemoryError OOM时自动保存堆文件,可以用visualvm分析堆文件

//收集器设置 
-XX:+UseSerialGC:设置串行收集器 
-XX:+UseParallelGC:设置并行收集器 
-XX:+UseParalledlOldGC:设置并行年老代收集器 
-XX:+UseConcMarkSweepGC:设置并发收集器

//垃圾回收统计信息 
-XX:+PrintGC 
-XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps 
-Xloggc:filename

//并行收集器设置 
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数.并行收集//线程数. 
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间 
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比.公式为1/(1+n)
//并发收集器设置 
-XX:+CMSIncrementalMode:设置为增量模式.适用于单CPU情况. 
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数.并行收集线程数.

用法

Idea用法
  1. 打开idea
  2. 点击右上角 edit configurations
  3. 在vm options输入参数

Springboot用法

由于笔者一直用的是Springboot,因此这边以Springboot的形式进行示范,在启动项目jar包时添加参数。

java -jar -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms1024m -Xmx1024m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC newframe-1.0.0.jar

工具使用

Visual VM

Visual VM 由java编写,已经被jdk集成,通过检测 JVM 中加载的类和对象信息等帮助我们分析内存使用情况,是用来分析java项目 、调优的利器,功能强大。

概述:显示了项目的jvm参数。
这边的禁用是什么原因呢?相信直播间的观众应该都是有智慧的!
监视: {} 暂时省略n个字。
线程: {} 暂时省略n个字。
抽样器: {} 暂时省略n个字。

jstat

1. 查看项目进程PId
  1. 笔者这边采用docker部署Springboot项目,所以只需要top或者jps就能直接查看到Pid。
  2. lsof -i:端口号,前提是你已经安装了。
  3. ps -ef | grep 项目名
2. 使用命令查看结果
jstat -gcutil 5 1000

实战分析

  1. 通过Visual VM发现,基本上每隔8分钟,jvm就会发生一次GC,而我本人也没有访问过项目,项目的访问量应该为0,所以在没有定时任务或者死循环的情况下,产生的对象数应该为0。理论上是不会发生GC的。
  2. 那么GC是发生在哪里的呢?年轻代还是老年代?
    由于这边NewRatio 为1,所以不管是老年代或者新生代发生gc一般都是在200m左右,我们不好分辨是哪个代。其实之前NewRatio=2xmx450m,发生GC的情况是150m。因此是新生代发生了GC。
  3. 如果不相信,下面是用jstat的截图,可以看出是新生代对象在不停的产生。

4. 知道是新生代发生了GC,基本上已经证明了上述的猜想:有个死循环。通过抽象分析器发现char对象非常大。

5. 接下来可以通过堆dump发现是哪几句代码出现了问题。可以使用jhat这个工具,文件可以通过Visual VM产生,当然在OOM的情况下,也可以通过参数产生。

jhat -J-Xmx1024M file

分析堆dump应该就可以发现了,这边就不分析了,其实是重启项目,映射多个端口,然后等待GC,就比较麻烦。为了更加贴近实际,该项目属于真实项目,已部署到阿里云,链接在此,猛戳我,代码来源于github。

结语

最后祝大家新年快乐,找到好工作。希望小智能拿个冠军,都看了十几年了,圆了老玩家的梦吧。