JVM性能优化之JVM调优

JVM性能优化之JVM调优


前言

通过前面的文章对JVM已经进行了简单的了解了,也知道了各种垃圾收集器以及其配置,那么这篇文章我们就简单地进行实例讲解了,如何进行JVM调优?JVM调优我们具体调整什么?为什么要调整这部分?怎么调整?

一、GC的评估指标

进行JVM调优主要针对下面几个方面:

  • 吞吐量: 吞吐量指的是运行用户代码占总时间的比例,它有一个计算公式为:吞吐量 = 应用程序运行的时间/ (应用程序运行的时间 + GC回收的时间); 举个例子,假设程序运行时间为100s,GC垃圾回收时间为1秒,则吞吐量为100/(1+100) = 99%;如果这个值越小代表着垃圾回收占用的时间越多,GC垃圾回收占用时间多的原因就是堆内存不足导致垃圾回收的频率太多
  • GC负荷: GC负荷是与吞吐量相对的一个概念,指的是GC花费时间的百分比;其计算公式为:GC负荷 = GC回收的时间/ (应用程序运行的时间 + GC回收的时间)
  • 响应时间: 这里的响应时间是GC执行垃圾回收时导致的STW的时间,这段时间除了GC其它所有线程都是停止的,当然我们期望的暂停时间越小越好。
  • GC频率: GC频率指的是在时间单位内GC进行垃圾回收的次数,当然GC频率与响应时间是反比的。假设堆内存一定的情况下,GC执行的频率越大代表着响应时间越小,而GC执行频率越小代表着响应时间越大。
  • 反应速度: 反应速度指的是一个对象变成垃圾一直到被回收所耗费的时间。

在我们讲垃圾回收的时候讲了一个收集器Parallel收集器,这个收集器就是注重吞吐量的,这个收集器是JDK默认的垃圾回收器。
响应时间优先的垃圾收集器,CMS收集器(老年代) /ParNew(新生代)。
G1收集器两者兼顾

二、怎么进行JVM调优

上面简单的说明了几个GC性能进行评估的指标,在实际操作中我们主要以吞吐量、响应时间优先,所以最终JVM调优后的代码我们期望看到的是高吞吐量+低响应时间

  1. 首先肯定需要考虑的是堆内存的大小,要合理的设置堆内存大小,怎么配置堆内存大小呢,这个可以借鉴腾讯云服务器给出的答案。
    在这里插入图片描述
    这是腾讯云服务器选型,按照选型的参照有一定访问量的我们就按照2G设置,并发适中的4G设置,并发比较大的设置8G+。当然这个是服务器的内存大小,但是这个默认服务器只有我们的应用程序没有其他很耗费内存的应用。
  2. 第二点启动的时候堆内存初始值和最大值保持一致,防止内存不足垃圾回收后导致的内存扩大浪费时间,包括像新生代等有初始值和最大值的都尽量设置为同样的参数。
  3. 不要去主动的调用System.gc()方法,会导致垃圾回收,而且是Full GC的,触发STW机制。
  4. 设置大对象存放参数,超过的放在老年代,因为大对象比较大在新生代里面拷过来拷过去的很浪费性能,而且会导致GC频繁,设置参数为:-XX:PretenureSizeThreshold
  5. 根据项目的情况合理的选择垃圾收集器,怎么选择垃圾收集器呢,这有个建议:还是按照上面的三种类型,2GB的使用Parallel收集器,这是以吞吐量优先的收集器,是默认的垃圾收集器,设置参数为 -XX:+UseParallelOldGC;对于4GB的使用CMS收集器,注重服务器的响应速度,系统停顿时间最短,设置参数为 -XX:+UseConcMarkSweepGC;对于8G甚至更大的使用G1收集器,将大内存设置成了多个小区域,而且回收按照区域优先级进行的,可以保证高吞吐量的同时做到低响应时间,设置参数为 -XX:+UseG1GC
  6. 设置了不同的垃圾收集器还要根据实际的GC日志进行分析来调整其他参数进行调优。
  7. 这是最重要的一点,其实大多数情况是代码不合格。其实优化代码带来的性能提升远比优化JVM参数要大的多。

三、如何分析内存溢出问题

先写个演示代,演示代码是一直进行死循环创建对象放到list中,这样创建的对象是可达的。

   public static void main(String[] args) throws InterruptedException {
        List list = new ArrayList();
        while (true){
            list.add(new String("123"));
        }
    }

打开jvisualvm分析工具后选中我们写的程序,找到抽样器进行内存抽样,下面两个图为抽样结果
在这里插入图片描述
首先看这张图,我们抽样出来的堆柱状图,这下面的列表是每种对象所使用的空间大小,没有告诉我们哪里导致的的内存溢出,但是我们可以得出结论创建的String对象太多导致了堆内存溢出。
再选中每个线程分配
在这里插入图片描述
看一下线程分配情况,这个列表是每个线程使用的堆内存大小,我们可以看到main线程占用了绝大部分的堆空间,几乎占满了,这个时候就可以定位到内存溢出可能是因为main线程创建了大量的String对象导致的,然后去排查main线程里面的代码是否有问题。
这里其实可以看到一个阿里巴巴开发规范中的提到的规范:每个线程都要创建一个属于自己的名字。有了这个线程名字是不是就查找起来方便多了,要是一堆线程名叫Thread1、Thread2。。。看到这个也找不到导致内存溢出的线程。

注意:GC分析的时候最好使用dump日志快照来分析,因为分析软件和应用程序两个应用之间建立通信导致的数据可能会造成干扰。

内容来源:蚂蚁课堂

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值