围绕垃圾收集和内存,您可以将 600 多个参数传递给JVM
。如果包括其他方面,则 JVM 参数总数将很容易超过 1000+。任何人都无法消化和理解太多的论据。在本文中,重点介绍了六个重要的JVM
参数,在Java性能测试
中起着非常重要的作用。
-Xmx 和-XX:MaxMetaspaceSize
-Xmx
可能是最重要的JVM
参数。-Xmx
定义要分配给应用程序的最大堆大小。。您可以这样定义应用程序的堆大小:-Xmx2g
。
堆大小在影响应用性能和所需物理硬件需求。这带来了一个问题,我的应用程序正确的堆大小是多少?我应该为应用程序分配大堆大小还是小堆大小?答案是:取决于需求和预算。
将-Xms
和-Xmx
设置为相同值的会提高 JVM 性能
元空间是将存储JVM
的元数据定义(例如类定义,方法定义)的区域。默认情况下,可用于存储此元数据信息的内存量是无限的(即受您的容器或计算机的 RAM 大小的限制)。您需要使用-XX:MaxMetaspaceSize
参数来指定可用于存储元数据信息的内存量的上限。
-XX:MaxMetaspaceSize=256m
GC 算法
OpenJDK 中有 7 种不同的 GC 算法:
- Serial GC
- Parallel GC
- Concurrent Mark & Sweep GC
- G1 GC
- Shenandoah GC
- Z GC
- Epsilon GC
如果您未明确指定 GC 算法,那么 JVM 将选择默认算法。在 Java 8 之前,Parallel GC
是默认的 GC 算法。从 Java 9 开始,G1 GC
是默认的 GC 算法。
GC 算法的选择对于确定应用程序的性能起着至关重要的作用。根据我们的研究,我们正在使用 Z GC 算法观察到出色的性能结果。如果使用JVM 11+
,则可以考虑使用Z GC
算法(即-XX:+ UseZGC
)。
下表总结了激活每种垃圾收集算法所需传递的 JVM 参数。
GC 算法 | JVM 参数 |
---|---|
Serial GC | -XX:+ UseSerialGC |
Parallel GC | -XX:+ UseParallelGC |
Concurrent Market & Sweep (CMS) GC | -XX:+ UseConcMarkSweepGC |
G1 GC | -XX:+ UseG1GC |
Shenandoah GC | -XX:+ 使用 ShenandoahGC |
Z GC | -XX:+ UseZGC |
Epsilon GC | GC -XX:+ UseEpsilonGC |
启用 GC 日志记录
垃圾收集日志包含有关垃圾收集事件,回收的内存,暂停时间段等信息,可以通过传递以下 JVM 参数来启用垃圾收集日志:
从 JDK 1 到 JDK 8:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:{file-path}
从 JDK 9 及更高版本开始:
-Xlog:gc*:file={file-path}
Demo:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/opt/workspace/myAppgc.log
-Xlog:gc*:file=/opt/workspace/myAppgc.log
通常,GC 日志用于调整垃圾回收性能。但是,GC 日志包含重要的微观指标。这些指标可用于预测应用程序的可用性和性能特征。在本文中将重点介绍一种这样的标尺:GC 吞吐量。GC 吞吐量是您的应用程序在处理客户交易中花费的时间与它在处理 GC 活动中花费的时间之比。假设您的应用程序的 GC 吞吐量为 98%,则意味着应用程序将其 98%的时间用于处理客户活动,其余 2%用于 GC 活动。
现在,让我们看一个健康的 JVM 的堆使用情况图:
您会看到一个完美的锯齿图案。您会注意到,当运行 Full GC(红色三角形)时,内存利用率将一直下降到最低。
现在,让我们看一下有问题的 JVM 的堆使用情况图:
您可以注意到,在图表的右端,即使 GC 反复运行,内存利用率也没有下降。这是一个典型的内存泄漏迹象,表明该应用程序正在存在某种内存问题。
如果您仔细观察一下该图,您会发现重复的完整 GC 开始在上午 8 点左右开始。但是,该应用程序仅在上午 8:45 左右开始获取 OutOfMemoryError。到上午 8 点,该应用程序的 GC 吞吐量约为 99%。但是,在上午 8 点之后,GC 吞吐量开始下降到 60%。因为当重复的 GC 运行时,该应用程序将不会处理任何客户交易,而只会进行 GC 活动。
-XX:+ HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath
OutOfMemoryError
是一个严重的问题,它将影响您的应用程序的可用性和性能。要诊断OutOfMemoryError
或任何与内存相关的问题,必须在应用程序开始遇到OutOfMemoryError
的那一刻或一瞬间捕获堆转储。由于我们不知道何时会抛出OutOfMemoryError
,因此很难在抛出时左右的正确时间手动捕获堆转储。但是,可以通过传递以下 JVM 参数来自动化捕获堆转储:
-XX:+ HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath = {HEAP-DUMP-FILE-PATH}
在-XX:HeapDumpPath
中,需要指定堆转储所在的文件路径。传递这两个 JVM 参数时,将在抛出OutOfMemoryError
时自动捕获堆转储并将其写入定义的文件路径。例:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/crashes/my-heap-dump.hprof
一旦捕获了堆转储,就可以使用HeapHero
和EclipseMAT
之类的工具来分析堆转储。
-Xss
每个应用程序将具有数十,数百,数千个线程。每个线程都有自己的堆栈。在每个线程的堆栈中,存储以下信息:
- 当前执行的方法/功能
- 原始数据类型
- 变量
- 对象指针
- 返回值。
他们每个都消耗内存。如果它们的使用量超出某个限制,则会引发StackOverflowError
。可以通过传递-Xss 参数来增加线程的堆栈大小限制。例:
-Xss256k
如果将此-Xss
值设置为一个很大的数字,则内存将被阻塞并浪费。假设您将-Xss
值指定为2mb
,而只需要256kb
,那么您将浪费大量的内存。
假设您的应用程序有 500 个进程,然后-Xss
值为2Mb
,则您的线程将消耗1000Mb
的内存。另一方面,如果您仅将-Xss
分配为256kb
,那么您的线程将仅消耗125Mb
的内存。每个 JVM 将节省875Mb
内存。
注意:线程是在堆(即-Xmx
)之外创建的,因此这1000Mb
将是您已经分配的-Xmx 值的补充。
-Dsun.net.client.defaultConnectTimeout 和-Dsun.net.client.defaultReadTimeout
现代应用程序使用多种协议(即 SOAP,REST,HTTP,HTTPS,JDBC,RMI)与远程应用程序连接。有时远程应用程序可能需要很长时间才能做出响应,有时它可能根本不响应。
如果没有正确的超时设置,并且远程应用程序的响应速度不够快,则您的应用程序线程/资源将被卡住。远程应用程序无响应可能会影响您的应用程序的可用性。它可以使您的应用程序停止磨削。为了保护应用程序的高可用性,应配置适当的超时设置。
您可以在 JVM 级别传递这两个强大的超时网络属性,这些属性可以全局适用于所有使用java.net.URLConnection
的协议处理程序:
sun.net.client.defaultConnectTimeout
:指定建立到主机的连接的超时(以毫秒为单位)。例如,对于 HTTP 连接,它是与 HTTP 服务器建立连接时的超时。当建立与资源的连接时,sun.net.client.defaultReadTimeout
指定从输入流读取时的超时(以毫秒为单位)。
例如,如果您要将这些属性设置为 2 秒:
-Dsun.net.client.defaultConnectTimeout=2000
-Dsun.net.client.defaultReadTimeout=2000
注意,默认情况下,这两个属性的值为-1,这表示未设置超时。
- 郑重声明:文章首发于公众号 “FunTester”,欢迎关注交流,禁止第三方转载、发表。
技术类文章精选
- Linux 性能监控软件 netdata 中文汉化版
- 性能测试框架第三版
- 图解 HTTP 脑图
- 性能测试中图形化输出测试数据
- 压测中测量异步写入接口的延迟
- 多种登录方式定量性能测试方案
- JMeter 吞吐量误差分析
- 多项目登录互踢测试用例