JMeter 压测教程之二 JVM 调优

大纲

JVM 简单介绍

JVM 内存结构

JVM 内存结构主要有三大块:栈、堆内存、方法区。堆内存是 JVM 中最大的一块。方法区存储类信息、静态变量、常量、常量池等数据,是线程共享的区域,为了与 Java 堆区分,方法区还有一个别名 Non-Heap (非堆)。栈又分为 Java 虚拟机栈和本地方法栈,主要用于方法的执行。

JVM 堆内存

所有的对象实例以及数组都要在堆内存上分配,堆内存是垃圾收集器管理的主要区域,也被称为 GC 堆。堆内存由新生代和老年代组成,不包括永久代(方法区);而新生代内存又被分成 Eden 空间、From Survivor 空间、To Survivor 空间,默认情况下新生代按照 8:1:1 的比例来分配。

提示

从 Java 8 开始,HotSpot 已经完全将永久代(Permanent Generation)移除,取而代之的是一个新的区域 — 元空间(MetaSpace)。

JVM 性能监控

为了方便监控 JVM 的性能,JDK 提供了 jconsolejvisualvm 工具,两者都可以通过命令行直接启动,支持监控本地和远程应用。值得一提的是,推荐使用 jvisualvm,因为它可以看作是升级版的 jconsole

Jconsole 监控

启动监控

  • 启动命令
1
$ jconsole
  • 运行界面

Jvisualvm 监控

jvisualvm(简称 VisualVM)可以监控内存泄露、跟踪垃圾回收、执行时内存分析、CPU 分析、线程分析等。

启动监控

  • 启动命令
1
$ jvisualvm
  • 运行界面

安装 GC 插件

为了方便查看 GC 的情况,jvisualvm 需要提前安装 Visual GC 插件。

  • 第一步:查看 JDK 版本
1
$ java -version
  • 第二步:浏览器打开 官方插件中心 的页面,根据 JDK 版本找到 Java VisualVM 的更新链接,例如 https://visualvm.github.io/archive/uc/8u40/updates.xml.gz

  • 第三步:菜单栏导航到 工具 -> 插件 -> 设置,点击 编辑 按钮,将 URL 更改为上面找到的 Java VisualVM 更新链接

  • 第四步:菜单栏导航到 工具 -> 插件 -> 可用插件,点击 检查最新版本 按钮,等插件列表更新成功后,勾选 Visual GC 项,最后点击 安装 按钮即可。

  • 第六步:重启 jvisualvm 后,选择要监控的应用,若在标签页中看到 Visual GC 页面,则说明 GC 插件安装成功。

JVM 性能监控指标

中间件监控指标

常用的中间件(如 Tomcat、Weblogic)监控指标,主要包括 JVM、ThreadPool、JDBC 等,具体如下:

  • 当前正在运行的线程数不能超过设定的最大值。一般情况下系统性能较好的情况下,线程数最小值设置为 50 和最大值设置为 200 比较合适。
  • 当前运行的 JDBC 连接数不能超过设定的最大值。一般情况下系统性能较好的情况下,JDBC 最小值设置为 50 和最大值设置为 200 比较合适。
  • GC 频率不能频繁,特别是 FULL GC 更不能频繁,一般情况下系统性能较好的情况下,JVM 最小堆大小和最大堆大小分别设置 1024M 比较合适。

数据库监控指标

常用的数据库(如 MySQL)监控指标,主要包括 SQL 性能、吞吐量、缓存命中率、锁、连接数等,具体如下:

  • SQL 执行耗时越小越好,一般情况下微秒级别。
  • 缓存命中率越高越好,一般情况下不能低于 95%。
  • 锁等待次数越低越好,等待时间越短越好。

中间件压测案例

以简单的电商商城项目为例,各中间件的压测结果如下:

总结

  • 中间件越多,性能损失越大,大多都损失在网络交互上。
  • 业务优化方向:数据库、模板页面的渲染速度、静态资源。

JVM 性能分析与调优

JVM 调优,调的是稳定,并不能让性能得到大幅提升。服务稳定的重要性就不用多说了,保证服务的稳定,GC 永远会是 JAVA 程序员需要考虑的不稳定因素之一。复杂和高并发下的服务,必须保证每次 GC 不会出现性能下降,各种性能指标不会出现波动,GC 回收规律而且干净,找到合适的 JVM 设置。FULL GC 最会影响性能,根据代码问题,避免 FULL GC 频率。可以适当调大年轻代的容量,让大对象可以在年轻代触发 YONG GC,调整大对象在年轻代的回收频次,尽可能保证大对象在年轻代回收,减小老年代缩短回收时间。

内置的 JVM 性能分析工具

JDK 内置了以下 JVM 性能分析工具,可以直接用于分析 JVM 性能,无需额外安装。

工具说明
jstack 查看 JVM 线程运行状态,是否有死锁现象等信息
jinfo 可以输出并修改运行时的 Java 进程的 opts
jps 与 Unix 上的 ps 命令类似,用来显示本地的 Java 进程,可以查看本地运行着几个 Java 程序,并显示它们的进程号
jstat 一个极强的监视 VM 内存工具。可以用来监视 VM 内存内的各种堆和非堆的大小及其内存使用量
jmap 打印出某个 Java 进程(使用 pid)内存内的所有 对象 的情况(如:产生哪些对象及其数量)

JVM 性能分析工具的使用

在使用下述工具前,建议先用 jps 命令获取当前的每个 JVM 进程号,然后选择要分析的 JVM 进程。

jstat 使用

jstat 工具特别强大,参数有众多的可选项,可详细地查看堆内各个部分的使用量,以及类加载的数量。使用时,需加上应用的进程 id 和所选参数。

命令说明
jstat -class pid 显示加载 Class 的数量,及所占空间等信息
jstat -compiler pid 显示 VM 实时编译的数量等信息
jstat -gc pid 显示 GC 的信息,查看 GC 的次数与时间
jstat -gccapacity pid 堆内存统计,包括堆内存的使用和占用大小
jstat -gcnew pid 新生代垃圾回收统计
jstat -gcnewcapacity pid 新生代内存统计
jstat -gcold pid 老年代垃圾回收统计
jstat -gcutil pid 堆内存(包括新生代、老年代)的垃圾回收统计

除了以上 pid 参数外,还可以同时加上两个数字,示例如下:

  • jstat -gcutil pid 1000 100: 每 1000 毫秒统计一次 GC 情况,一共统计 100 次
  • jstat -printcompilation pid 250 6: 表示每 250 毫秒打印一次,一共打印 6 次,还可以加上 -h3 参数使每三行显示一次标题

jinfo 使用

jinfo 是 JDK 自带的命令,可以用来查看正在运行的 Java 应用程序的扩展参数,包括 Java System 属性和 JVM 命令行参数;也可以动态地修改正在运行的 JVM 一些参数。当系统崩溃时,jinfo 可以从 core 文件里面知道崩溃的 Java 应用程序的配置信息。

命令说明
jinfo pid 输出当前 JVM 进程的全部参数和系统属性
jinfo -flag name pid 查看指定的 JVM 参数的值,打印结果: - 无此参数,`+ 有此参数
jinfo -flag [+/-]name pid 开启或者关闭对应名称的参数(无需重启虚拟机)
jinfo -flag name=value pid 修改指定参数的值
jinfo -flags pid 输出全部的参数
jinfo -sysprops pid 输出当前 JVM 进行的全部的系统属性

jmap 使用

jmap 命令可以生成堆内存的 Dump 文件,也可以查看堆内对象分析内存信息等,如果不使用这个命令,还可以使用 -XX:+HeapDumpOnOutOfMemoryError 参数来让虚拟机在出现 OOM 的时候自动生成 Dump 文件。

命令说明
jmap -dump:live,format=b,file=product.dump pidDump 堆内存到指定的文件,format 指定输出格式,live 指明是活着的对象,file 指定文件名。Eclipse 可以直接打开这个文件
jmap -heap pid 打印堆内存的概要信息,包括 GC 使用的算法、堆内存的配置和使用情况,可以用此来判断目前内存的使用情况以及垃圾回收情况
jmap -finalizerinfo pid 打印等待回收的对象信息
jmap -histo:live pid 打印堆的对象统计,包括对象数、内存大小等。特别注意,这个命令执行,JVM 会先触发一次 GC,然后再统计信息
jmap -clstats pid 打印 Java 类加载器的智能统计信息,对于每个类加载器而言,它的名称、活跃度、地址、父类加载器、加载的类的数量和大小都会被打印。此外,包含的字符串数量和大小也会被打印

-F 参数表示强制模式。如果指定的 pid 没有响应,请使用 jmap -dumpjmap -histo 选项。此模式下,不支持 live 子选项。使用示例:jmap -F -histo pid

jstack 使用

jstack 是 JDK 自带的线程堆栈分析工具,使用该命令可以查看或导出 Java 应用程序中的线程堆栈信息。

命令说明
jstack pid 输出当前 JVM 进程的线程堆栈信息
jstack -l pid > thread_dump.txt 将当前 JVM 进程的线程堆栈信息 dump 出来,存储在指定的文件中

其他 JVM 性能分析工具

GCViewer

GCViewer 是一个图形化的 GC 日志分析工具,用于帮助用户理解 GC 的行为,分析停顿时间和 GC 的效率。

GCeasy

GCeasy 是一款在线的 GC 日志分析工具,可以通过 GC 日志分析进行内存泄漏检测、GC 暂停原因分析、JVM 配置建议优化等功能,而且是可以免费使用的(有一些服务是收费的)。

Arthas

Arthas(阿尔萨斯)是阿里巴巴开源的一款 Java 诊断工具,用于实时检测、诊断 Java 应用程序的性能问题。它是一个命令行工具,提供了丰富的功能,包括查看类加载信息、方法执行耗时、线程堆栈、内存分析等。Arthas 的设计目标是在生产环境中实时诊断和解决 Java 应用程序的问题。

MAT

MAT(Memory Analyzer Tool),一个基于 Eclipse 的内存分析工具,是一个快速、功能丰富的 Java heap 分析工具,它可以帮助查找内存泄漏和减少内存消耗。

参考博客