JVM调优

JVM调优

面试真题:说一下JVM调优

  • JVM调优问题一般分为四个步骤
  • 第一步:发现问题,即运用JVM监控工具监控服务器运行时情况,做好告警阈值,通过告警工具设置告警,方便及时介入问题保留现场。
  • 第二步:分析问题,根据现场,保留JVM运行时内存,CPU,IO,GC,线程,请求量等,甚至阈值时打印的GC日志,以及Dump的堆内存情况
    • 找方向:根据掌握情况,分析具体原因,硬件问题,软件问题,配置问题,代码问题,系统问题等方向
    • 找原因:根据方向,找到最终原因,提出有针对性优化方向
    • 注意:很多情况下是代码问题导致,
  • 第三步:解决问题,根据分析问题结果,解决问题。
  • 第四步:验证结果:基于严谨,可以在灰度或压测环境,验证新解决的方案,没有问题再上生产

生产调优详细过程

  • 第一步:发现问题-监控告警
    • 运用普罗米修斯,阿尔萨斯,阿里Arams等或者devops工具对运行情况监控。
    • 运用钉钉告警等工具,出现设置的阈值时进行告警,运维人员及时解决异常干预。同时dump保留现场情况。
  • 第二步:分析问题-有针对性分析
    • 分析问题现场,例如:内存,CPU,线程,GC,访问超时,访问异常等情况表现,例如内存暴增,CPU暴增,线程数量变化,GC频繁,频繁报错等
    • 有条件则分析dump的内存情况,通过MAT工具分析堆内存对象情况,线程死锁等情况,定位代码出现问题地方,优化代码。
    • 对于GC问题,通过打印JVM日志分析GC过程,查看GC前后的年轻代,老年代的回收情况。
    • 重要的是结合当前系统情况,以及访问情况分析
  • 第三步:解决问题–提解决方案
    • 根据分析问题结果,提出解决方案
    • 例如内存使用率暴增:分析堆内存,查看对象占用问题,是否有内存泄漏,是否加载超大对象,
    • 例如CPU使用率暴增:分析是否有比较吃CPU的方法或循环依赖等情况。
    • 例如频繁GC等:是否年轻代或老年代分配过小,比率是否正确,
  • 第四步:验证结果
    • 修改配置或修改代码后,可以在灰度环境压测,没有问题再上生产
    • 可以尝试多个方案的压测效果,选择成本最小,效果最好的上生产。

优化各个环节落地

  • 监控指标

    • 通过监控工具
      • 堆内存占用比率
      • 线程数量比率
      • FullGC情况
      • 程序错误情况
    • 通过打印GC日志
      • 设定触发dump出实时内存情况
      • 打印FullGC的情况
      • 通过下载GC的dump文件
    • 了解服务器机器参数
      • CPU核数
      • 内存大小
      • 集群模式
      • 数据库服务
      • JDK版本
  • 监控告警工具

    • jps 查看当前虚拟机运行的jar项目
    • jinfo 查看和调整JVM启动和运行参数
    • jstack 虚拟机线程信息监控
    • jstat 查看JVM的统计信息
      • jstat –gcutil -h 20 pid 1000 100
      • jstat -gccause -h 20 pid 1000 100
    • jmap JVM内存占用信息和快照信息
      • 手动获取dump:jmap -dump:format=b,file=filename.hprof pid
      • 被动获取dump: -XX:+HeapDumpOnOutOfMemoryError - - -XX:HeapDumpPath=/tmp/heapdump.hprof
      • 获取dump后通过MAT工具分析堆内存占用情况
    • GCeasy分析GC日志的在线网站,根据GC日志查看数据
    • MAT工具-内存分析工具 [离线常用]
      • IBM Memory Analizer 内存分析工具
      • JvisualVM JDK自带离线分析工具
      • JMC工具,用来追溯热点代码和热点线程
        • 先录制,分析线程 内存 锁 文件 Socket 方法调用 垃圾回收 JIT TLAB 等
    • OQL 工具:类似于SQL语句,查看内存中的对象占用情况
    • 基准测试 JMH 单元测试形式测试多线程情况
    • Arthas在线分析工具[测试环境常用]
      • 在线分析类加载以及异常
      • 在线查看代码执行流程,查看反编译的代码
      • 在线调试,在线debug以及事故重现
      • JVM运行监控
      • 监控JVM的实时运行情况
    • 普罗米修斯的线上监控工具[生产常用]
      • 内存和CPU负载
      • 线程数量
      • GC情况
      • 请求量和并发量监控
  • 分析问题工具

    • 通过MAT工具
      • BMAT工具,堆内存分析统计,堆内存对象分析,用于分析内存泄漏原因
      • JVM工具:用于在线分析和离线分析,堆内存分析,线程分析
    • 通过GCeasy分析工具
      • 年轻代,老年代,元空间,整体的最大值最小值分析
      • 吞吐量指标,百分比越高GC开销月底
      • GC延迟指标,平均GC暂停时间和最大暂停时间分析
      • 时间线可视化加过:判断GC的时间点以及GC内存
      • GC统计:统计年轻代,老年代,元空间,FullGC等指标
      • GC原因分析,
    • 通过arthas在线分析
    • 通过VM工具在线分析
      • 分析点
        • 堆内存的年轻代的回收比率
        • 堆内存老年代的回收比率
        • 堆内存元数据的回收比率

优化方案-视具体情况分析

  • 内存飙升,居高不下
    • 内存泄漏问题
      • 系统资源在堆栈线程错误使用情况下,使用完毕的资源无法回收问题
      • 通过打印堆内存泄漏
      • 分析内存泄漏的原因
    • 通过MAT工具分析堆内存,分析例如:缓存使用不合理导致,全局对象未回收,大对象过多,对象嵌套过深等
    • 请求飙升导致,可以使用集群,增加服务器,
  • CPU飙升,居高不下
    • 凭经验分析:例如内部有大型的公式计算,不合理的算法等
    • 通过Jstack等分析,一些特殊情况:例如不合理使用大量正则,循环调用,并发线程不合理等
  • IO负载过高
    • 频繁读写磁盘文件,频繁请求外部文件等情况,可以采用零拷贝,外部缓存等方式
    • 可能是堆外内存泄漏,考虑Netty,Dubbo等不合理使用导致。
  • 频繁GC-结合printGC日志分析
    • 调整堆内存,单个线程栈内存,元空间等大小
    • 调整年轻代,老年代的比率,阈值等
    • 通过MAT可以查看堆内存情况,找到问题代码,进行代码优化,例如减少大对象生成
    • 调整GC回收器类型,例如并发回收器改为CMS,CMS回收器改为G1回收器等
  • 提高吞吐量和并发量
    • 吞吐量和并发量是衡量系统高性能标准
    • 优化java代码
    • 优化JVM参数配置,垃圾回收器种类等

生产调优实战

  • 1、提前做好JVM内存监控以及阈值预警
  • 2、针对不同的情况做对应的分析,
    • 能够在五分钟内解决就快速修复上线,否则就考虑回滚
  • 3、响应延迟问题:【考虑线程阻塞】
    • 通过JSP查看存活线程,以及存活时间,定位出现阻塞问题的线程
  • 4、内存暴增问题:【考虑内存泄漏】
    • 通过dump堆内存,通过IAM或VM等工具分析内存,找到堆内存中对象,从而定位问题,解决问题
  • 5、频繁GC造成卡顿问题:考虑JVM配置不合理
    • 通过分析QPS,考虑是否要增加堆内存大小,栈内存,线程栈内存的大小
    • 通过dump虚拟机的GC日志,分析youngGC,minioGC,OldGC分析堆内存的年轻代老年代的比率
    • 通过GC的停顿时间,考虑是否需要更换年轻代和老年代的回收器组合,并配置回收器的参数
  • 6、上线前预防
    • 在非生产环境安装althas工具,分析虚拟机的线程堆栈以及代码问题,定位快

开发中碰到的JVM调优问题

  • 发现JVM在访问量高的时候频繁GC-上线一个新功能后发现GC频繁,几乎几分钟一次,通过dump代码后发现是JVM堆内存的年轻代和老年代配置过小导致
  • 发现JVM的内存在上线内存使用率暴增-例如上线OKHTTP后访问发现内存飙升,最后通过dump对内存后分析发现是OKhttp的连接存在内存泄漏问题
  • 发现JVM的IO频繁问题-上线后发现某个访问接口频繁超时异常,但是JVM的内存,GC都是正常,dump下堆内存后分析发现是shardingjdbc的连接池过小,而且没有使用分表键。

你可能感兴趣的:(jvm)