JVM系列【6】GC与调优3

Stella981
• 阅读 767

JVM系列笔记目录

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

调优前的基础概念

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

什么是调优

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

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

    步骤

    1. ​ 熟悉业务场景
    2. 选择回收器组合,没有最好的GC,只有最适合的GC。追求响应时间或停顿时间选择CMS、G1、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. 提供一个简单的案例分析。

      有一个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 ,一定要找到是哪个线程持有这把锁。 怎么找?搜索jstack dump的信息,找 ,看哪个线程持有这把锁处于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 装入分析,界面友好且支持复杂查询
    
    1. 最难的一点:定位到代码中的问题
    > 示例代码的问题是:线程池使用不当引起OOM;不停new CardInfo对象不停地起定时线程去处理,导致这些对象越来越多
    

知识分享,转载请注明出处。学无先后,达者为先!

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
JAVA工程师成神道路
一、基础篇1.1JVM1.1.1.Java内存模型,Java内存管理,Java堆和栈,垃圾回收http://www.jcp.org/en/jsr/detail?id133http://ifeve.com/jmmfaq/1.1.2.了解JVM各种参数及调优1.1.3.
Stella981 Stella981
3年前
JVM(6):JVM 调优
JVM(6):JVM调优从Eclipse开始来源:纯洁的微笑,www.cnblogs.com/ityouknow/p/5647513.html概述什么是jvm调优呢?jvm调优就是根据gc日志分析jvm内存分配、回收的情况来调整各区域内存比例或者gc回收的策略;更深一层就是根据dump出来的内存结构和线程栈来
Wesley13 Wesley13
3年前
Java工程师成神之路
一、基础篇1.1JVM1.1.1.Java内存模型,Java内存管理,Java堆和栈,垃圾回收http://www.jcp.org/en/jsr/detail?id133http://ifeve.com/jmmfaq/1.1.2.了解JVM各种参数及调优
Stella981 Stella981
3年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Stella981 Stella981
3年前
JVM系列【6】GC与调优2
JVM系列笔记目录虚拟机的基础概念class文件结构class文件加载过程jvm内存模型JVM常用指令GC与调优了解HotSpot常用命令行参数JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/
Stella981 Stella981
3年前
JVM系列【4】内存模型
JVM系列笔记目录虚拟机的基础概念class文件结构class文件加载过程jvm内存模型JVM常用指令GC与调优硬件层数据一致性\存储器层次结构!file(https://oscimg.oschina.net/osc
Stella981 Stella981
3年前
JVM系列【6】GC与调优1
JVM系列笔记目录虚拟机的基础概念class文件结构class文件加载过程jvm内存模型JVM常用指令GC与调优GC基础知识什么是垃圾​没有任何引用指向的一个对象或多个对象(循环引用)!file(https:
Stella981 Stella981
3年前
JVM系列【6】GC与调优6
JVM系列笔记目录虚拟机的基础概念class文件结构class文件加载过程jvm内存模型JVM常用指令GC与调优GC常用参数\XmnXmsXmxXss年轻代最小堆最大堆栈空间\XX:UseTLAB使用