JVM面试与调优(2)-JVM调优概述

比眉伴天荒 2022-08-29 10:08 266阅读 0赞

【订阅专栏合集,作者所有付费文章都能看】

本专栏以极其精炼、通俗的语言梳理了Java虚拟机(JVM)的相关知识。此乃居家旅行、跳槽面试必备之物,望笑纳。

我的专栏文章很长,你要忍一下!

JVM面试题与调优专栏将分为3章。第一章讲解JVM的结构;第二章讲解垃圾回收;第三章讲解JVM调优实战技术和工具使用。本篇为第三章开篇,主要讲解 JVM 的调优工具。《JVM面试与调优》专栏地址:https://blog.csdn.net/hellozpc/category_10959501.html


推荐【JVM与调优实战】https://blog.csdn.net/hellozpc/category_10959501.html
推荐【Kafka】https://bigbird.blog.csdn.net/article/details/108770504
推荐【rabbitmq】https://bigbird.blog.csdn.net/article/details/81436980
推荐【Flink】https://blog.csdn.net/hellozpc/article/details/109413465
推荐【SpringBoot】https://blog.csdn.net/hellozpc/article/details/107095951
推荐【SpringCloud】https://blog.csdn.net/hellozpc/article/details/83692496
推荐【Mybatis】https://blog.csdn.net/hellozpc/article/details/80878563
推荐【SnowFlake】https://blog.csdn.net/hellozpc/article/details/108248227
推荐【并发限流】https://blog.csdn.net/hellozpc/article/details/107582771


文章目录

    • JVM调优概述
      • 为什么要调优
      • 调优的依据
      • 调优的阶段
      • 调优的方向
      • 调优的步骤
      • 调优的评价

JVM调优概述

为什么要调优

很多小伙伴在实际开发中很少会遇到需要对jvm进行优化的需求。但是要知道,在生产环境中,随着程序的运行,用户量、访问量的增多,一些性能问题就会逐步显现出来。尤其是to C的一些应用,比如打车软件,可能随着开城数量的增加,用户数就会不断地增加。平时跑得好好的代码,在用户数激增时就可能会暴露出一些性能缺陷。比如后端服务突然卡顿、日志不输出、程序没有反应,服务器的CPU负载、内存消耗突然升高。GC日志不断输出,且伴有频繁的FullGC,甚至出现了OOM。此时就需要我们能够基于自己所掌握的JVM理论知识和分析工具对程序进行分析,找出暗藏的性能缺陷,并改善既有代码。

调优的依据

  • 程序运行日志

    JAVA应用程序一般都会集成日志框架,用以在程序执行过程中输入日志信息。目前比较受欢迎的日志框架比如log4j2、logbak。通常我们在程序中的关键位置,都会手动记录一些日志信息,比如输出异常堆栈信息,便于排除分析问题。

  • GC日志

    一般线上运行的程序,我们都会开启GC日志输出。通过分析GC日志能够掌握一些程序运行时的情况。

    比如在启动JAVA程序时,使用下列JVM参数开启GC日志输出到指定文件:

    1. -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/usr/log/myapp-gc.log
  • 线程快照

    可以通过一些工具,比如jdk自带的jstack命令抓取正在运行的Java进程的线程快照,来分析进程中各个线程的运行情况。如果有等待(wait)状态或者阻塞(blocked)状态的线程,那么可以分析其原因。

    1. jstack 进程id > mythread.log
  • 堆内存快照

    我们知道Java对象都是存储在JVM自己管理的堆空间中,即通常我们所说的堆内存。Java程序启动时可以通过JVM参数指定其运行的堆内存大小。程序异常时我们可以使用jdk自带的命令或者其它第三方工具来dump堆快照文件,分析堆内存的使用情况,找出占用大量内存空间的“罪魁祸首”。比如使用下列命令:

    1. jmap -dump:format=b,file=c:\myheap.hprof ${ pid}

    当然也可以在程序启动时指定jvm参数使得在程序发生OOM时,自动导出应用程序的当前快照文件到指定路径。

    1. -Xmx300m -Xms300m -Xmn110m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\myheap.hprof

调优的阶段

  • 上线前

    上线前,我们可以对自己的代码进行自测,及时发现问题;此外,如果有数量比较大的场景,还建议进行压测。通过大量造数据,对程序进行压测,能够及时暴露潜在的性能问题。且在本地自测时,可以方便地使用GUI分析工具。

  • 上线后

    通过对线上程序的监控,包括业务日志监控,机器资源使用监控,异常监控等手段及时发现问题。

调优的方向

  • 代码正确性

    优化的本质是对我们的应用程序优化,因此代码的正确性是最基础的保证。平时开发中,我们除了自测之外,还可以通过小组code review等方式来进一步收集合理的优化建议,保证质量。

  • 合理利用硬件资源

    如果给程序分配的机器资源得不到充分利用,则某种意义上是对公司或者个人“财产”的浪费。因此要充分压榨机器的资源,比如使用线程池,提高线程数。 使用打批方式处理数据时,根据可用的资源合理控制批次大小,力求资源利用率最大化。

  • 合理进行JVM设置

    通过对业务量的评估,合理设置JVM运行时参数,充分压榨机器物理资源。根据实际的运行情况,及时调整设置,以满足需求。

调优的步骤

  • 发现问题

    实际生产中,我们可以通过监控系统,或者手动查看日志去发现问题。比如cpu load过高、GC频繁,甚至发生OOM。或者程序响应时间较长,各种超时,甚至线程死锁。

  • 排查问题

    运用命令行工具jstack、jmap、jinfo等分析程序的运行情况。dump出运行程序的堆文件、线程信息文件,线下使用内存分析和线程分析工具分析文件。也可以使用GUI工具,比如jconsole、JVisualVM或者阿里的Arthas来实时查看JVM状态。

  • 解决问题

    根据分析的结果,判断是否需要优化。

    比如在物理层面:适当增加内存;增加机器,分散单个节点压力;

    在代码优化层面:控制内存使用、合理设置线程池线程数量;

    在配置层面:根据业务背景选择合适的垃圾回收器;设置合理的-Xms、-Xmx等参数;

    在中间件层面:考虑使用中间件提高程序效率,比如使用redis缓存、消息队列等。

调优的评价

  • CPU/内存占用情况

    通过监控系统,或者登录机器通过top等命令查看资源使用率,查看CPU、堆内存的使用率是否处于合理区间。

  • 并发数

    同一时刻,对服务器有实际交互的请求数。评估系统能够支撑的并发数的大小是否满足当前及后续的业务需求。

  • 吞吐量

    对单位时间内完成的工作量(请求)的量度。

    在JVM中,吞吐量是指:运行用户代码的时间占总运行时间的比例(总运行时间=程序的运行时间+GC时间)。

  • 响应时间

    提交请求到请求返回所花费的时间。一般响应时间越短,系统吞吐量越大。如果处理响应时正好赶上了GC,那么GC时工作线程暂停的时间也将计入总的耗时。由此可见,频繁的GC会影响系统的响应时间。

    可以通过JVM参数设置最大GC等待时间(毫秒)。

    1. -XX:MaxGCPauseMillis = 50

    如果设置了每次GC最大的停顿毫秒数,JVM将调整Java堆大小和其他与GC相关的参数,以使GC引起的暂停时间小于设置的毫秒数,尽可能地保证内存回收耗时不超过设定值。注意:该参数如果设置太小,将导致系统花费过多的时间进行垃圾回收。因为要满足最大暂停时间限制,JVM将设置更小的堆,以存储相对少量的对象,来提升回收速率,反而会导致更高频率的GC。

  • 各个指标间关系

    一般而言,并发数比较小时,响应时间也会比较短,此时的吞吐量也相对较小;并发数增大时,响应时间相应地增加,此时总的吞吐量也增大。当并发量进一步增大时,由于响应时间变慢,反而可能会导致吞吐量降低,直到资源耗尽,甚至程序卡死。

    JVM调优时主要关注CPU/内存占用情况以及JVM吞吐量

发表评论

表情:
评论列表 (有 0 条评论,266人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JVM

    一、JVM调优的监控方法 jvm在对进行问题排查,线程等关注问题,在理解jvm的内存分配和垃圾回收,java类的编译和加载等等理论知识的前提下要学会使用工具去观察jvm中的实

    相关 JVM

    1. 年轻代大小选择 (1) 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到

    相关 spark JVM

    我们的堆内存分为:新生代,和年老代, 年轻代又分为:Eden区,幸存一区,幸存二区, 每一次访对象的时候,都是放入eden区域,和其中的一个幸存一区中,幸存二区是不放对象的

    相关 JVM

    前提: 某大型跨境电商业务发展非常快,线上机器扩容也很频繁,但是对于线上机器的运行情况,特别是jvm内存的情况,一直没有一个统一的标准来给到各个应用服务的owner。经过6

    相关 JVM

    年轻代大小选择 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对

    相关 JVM

    JVM调优是所有初级程序员向高级迈入的必经之路,而这个过程又需要许多JVM内存知识。下面就总结一二,和大家分享一下: 1.JVM内存模型 JVM内存模型如下图所示: