JVM面试与调优(2)-JVM调优概述
【订阅专栏合集,作者所有付费文章都能看】
本专栏以极其精炼、通俗的语言梳理了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日志输出到指定文件:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/usr/log/myapp-gc.log
线程快照
可以通过一些工具,比如jdk自带的jstack命令抓取正在运行的Java进程的线程快照,来分析进程中各个线程的运行情况。如果有等待(wait)状态或者阻塞(blocked)状态的线程,那么可以分析其原因。
jstack 进程id > mythread.log
堆内存快照
我们知道Java对象都是存储在JVM自己管理的堆空间中,即通常我们所说的堆内存。Java程序启动时可以通过JVM参数指定其运行的堆内存大小。程序异常时我们可以使用jdk自带的命令或者其它第三方工具来dump堆快照文件,分析堆内存的使用情况,找出占用大量内存空间的“罪魁祸首”。比如使用下列命令:
jmap -dump:format=b,file=c:\myheap.hprof ${ pid}
当然也可以在程序启动时指定jvm参数使得在程序发生OOM时,自动导出应用程序的当前快照文件到指定路径。
-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等待时间(毫秒)。
-XX:MaxGCPauseMillis = 50
如果设置了每次GC最大的停顿毫秒数,JVM将调整Java堆大小和其他与GC相关的参数,以使GC引起的暂停时间小于设置的毫秒数,尽可能地保证内存回收耗时不超过设定值。注意:该参数如果设置太小,将导致系统花费过多的时间进行垃圾回收。因为要满足最大暂停时间限制,JVM将设置更小的堆,以存储相对少量的对象,来提升回收速率,反而会导致更高频率的GC。
各个指标间关系
一般而言,并发数比较小时,响应时间也会比较短,此时的吞吐量也相对较小;并发数增大时,响应时间相应地增加,此时总的吞吐量也增大。当并发量进一步增大时,由于响应时间变慢,反而可能会导致吞吐量降低,直到资源耗尽,甚至程序卡死。
JVM调优时主要关注CPU/内存占用情况以及JVM吞吐量。
还没有评论,来说两句吧...