JVM系列【6】GC与调优3

2020年10月18日 阅读数:6
这篇文章主要向大家介绍JVM系列【6】GC与调优3,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

JVM系列笔记目录

  • 虚拟机的基础概念
  • class文件结构
  • class文件加载过程
  • jvm内存模型
  • JVM经常使用指令
  • GC与调优

调优前的基础概念

  1. 吞吐量:用户代码时间 /(用户代码执行时间 + 垃圾回收时间)
  2. 响应时间:STW越短,响应时间越好
  3. 所谓调优,首先肯定,追求啥?吞吐量优先,仍是响应时间优先?仍是在知足必定的响应时间的状况下,要求达到多大的吞吐量。如科学计算、数据挖掘:吞吐量优先;网站、GU、 API 等追求响应时间。

什么是调优

  1. 根据需求进行JVM规划和预调优
  2. 优化JVM运行环境(慢、卡顿)
  3. 解决JVM运行过程当中出现的各类问题(如OOM)
  • 根据需求进行JVM规划和预调优

    调优通常来讲,从业务场景开始,没有业务场景的调优都是耍流氓;无监控 (压力测试,能看到结果),不调优。java

    步骤面试

    1. ​ 熟悉业务场景
    2. 选择回收器组合,没有最好的GC,只有最适合的GC。追求响应时间或停顿时间选择CMS、G一、ZGC追求吞吐量 可选择PS。
    3. 计算内存需求(经验值 1.5G -16G)
    4. 选定CPU(越高越好)
    5. 设定年代大小,升级年代
    6. 设定日志参数,日志文件全放一个?10T日志怎么查。能够设置滚动日志如 -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause, 或是天天产生一个日志文件。
    7. 观察日志状况

    提供一个简单的案例分析服务器

    案例1:垂直电商,最高每日百万订单,处理订单系统须要什么样的服务器配置?

    这个问题比较业余,由于不少不一样的服务器配置都能支撑(1.5G -16G)。能够具体分析:一天中特定的高峰期1小时有360000订单集, 1000个订单/秒,能够根据经验值估算须要的内存配置。若是非要要计算,能够这么算:一个订单产生须要多少内存?512K * 1000,须要500M内存。多线程

    从另外专业的角度考虑:要求响应时间100ms,这种状况下能够经过压测的方式找到符合的服务器配置。运维

  • 优化JVM运行环境(慢、卡顿)
    1. 提供一个简单的案例分析。jvm

      有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆.用户反馈网站比较缓慢,所以公司决定升级。新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比之前效率更低了。工具

      1. 为何原网站慢?不少用户浏览数据,不少数据load到内存,内存不足,频繁GC,STW长,响应时间变慢。
      2. 为何会更卡顿?内存越大,FGC时间越长
      3. 如何解决?能够换垃圾回收器,如从PS 换为PN + CMS 或者是1.8以上的直接用G1。
    2. 系统CPU常常100%,如何调优?(面试高频)测试

      CPU100%那么必定有线程在占用系统资源,优化

      1. 找出哪一个进程cpu高(top)
      2. 该进程中的哪一个线程cpu高(top -Hp)
      3. 导出该线程的堆栈 (jstack)
      4. 查找哪一个方法(栈帧)消耗时间长 (jstack)
      5. 对比工做线程占比高仍是垃圾回收线程占比高
    3. 系统内存飙高,如何调优(面试高频)网站

      思路: 导出堆内存(jmap); 使用工具如(jhat jvisualvm mat jprofiler)分析
  • 解决JVM运行过程当中出现的各类问题

    提供一个测试案例来讲明分析过程和经常使用的工具,代码以下:

    /**

*/

public class T15_FullGC_Problem01 {

  private static class CardInfo {
      BigDecimal price = new BigDecimal(0.0);
      String name = "张三";
      int age = 5;
      Date birthdate = new Date();

      public void m() {}
  }

  private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
          new ThreadPoolExecutor.DiscardOldestPolicy());

  public static void main(String[] args) throws Exception {
      executor.setMaximumPoolSize(50);

      for (;;){
          modelFit();
          Thread.sleep(100);
      }
  }

  private static void modelFit(){
      List<CardInfo> taskList = getAllCardInfo();
      taskList.forEach(info -> {
          // do something
          executor.scheduleWithFixedDelay(() -> {
              //do sth with info
              info.m();

          }, 2, 3, TimeUnit.SECONDS);
      });
  }

  private static List<CardInfo> getAllCardInfo(){
      List<CardInfo> taskList = new ArrayList<>();

      for (int i = 0; i < 100; i++) {
          CardInfo ci = new CardInfo();
          taskList.add(ci);
      }

      return taskList;
  }

}


1. 启动命令`java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError T15_FullGC_Problem01`

2. 通常是运维团队首先受到报警信息(CPU、Memory)

3. top命令观察到问题:内存不断增加,CPU占用率居高不下

4. top -Hp 观察进程中的线程,哪一个线程CPU和内存占比高

5. jps定位具体java进程;jstack  pid  定位线程情况,重点关注:WAITING BLOCKED

   >  waiting on <0x0000000088ca3310> (a java.lang.Object)
   >    假若有一个进程中100个线程,不少线程都在waiting on <xx> ,必定要找到是哪一个线程持有这把锁。   怎么找?搜索jstack dump的信息,找<xx> ,看哪一个线程持有这把锁处于RUNNABLE状态。

6. jinfo pid 查看JVM的状况,通常用处不大。

7. 经过jstat -gc 动态观察gc状况;或是阅读GC日志发现频繁GC;或是经过arthas观察gc状况。

8. 在线定位,查找有多少对象产生,注意大量的对象,使用`jmap -histo pid |head -20`

9. `jmap -dump:format=b,file=xxx pid `能够在线堆转储,可是要慎重影响很大。

   > 线上系统内存特别大,jmap执行期间对进程产生很大影响,甚至卡顿(电商不适合)。
   >
   > 如何解决? 启动时候设定参数HeapDumpOnOutOfMemoryError,OOM的 时候会自动产生堆转储文件;若是线上不少服务器备份(高可用),停掉这台服务器对其它服务没影响也能够在线堆转储;在线定位也能够用阿里的arthas。

10. 使用MAT/jhat/jvisualvm 进行dump文件分析。

    > 建议使用MAT/jvisualvm 装入分析,界面友好且支持复杂查询

11. 最难的一点:定位到代码中的问题

    > 示例代码的问题是:线程池使用不当引发OOM;不停new CardInfo对象不停地起定时线程去处理,致使这些对象愈来愈多