当前位置: 首页 > 科技观察

高效应用程序应配置的七个JVM参数

时间:2023-03-21 20:43:07 科技观察

图片围绕垃圾收集和内存,您可以将600多个参数传递给JVM。如果包括其他方面,JVM参数计数很容易超过1000+。争论太多,任何人都无法消化和理解。在本文中,我们将重点介绍您可能会发现有用的七个重要JVM参数。1.-Xmx和-XX:MaxMetaspaceSize-Xmx可能是最重要的JVM参数。-Xmx定义分配给应用程序的最大堆大小。您可以像这样定义应用程序的堆大小:-Xmx2g这就提出了一个问题,我的应用程序的正确堆大小是多少?我应该为我的应用程序分配大堆大小还是小堆大小?答案是:看你的服务需要多少内存来承载预期的流量,你可以通过压测或者实际在线流量来获取。元空间是JVM的元数据定义(例如类定义、方法定义)将被存储的区域。默认情况下,可用于存储此元数据信息的内存量是无限的(即受容器或机器的RAM大小限制)。您需要使用-XX:MaxMetaspaceSize参数来指定可用于存储元数据信息的内存量的上限。-XX:MaxMetaspaceSize=256m2。GC算法OpenJDK中目前有7种不同的GC算法:SerialGCParallelGCConcurrentMark&SweepGCG1GCShenandoahGCZGCEpsilonGC如果你没有明确指定一个GC算法,那么JVM会选择默认的算法。在Java8之前,并行GC是默认的GC算法。从Java9开始,G1GC是默认的GC算法。GC算法的选择在决定应用程序的性能方面起着至关重要的作用。根据我们的研究,我们正在观察ZGC算法的出色性能结果。如果您使用JVM11+运行,那么您可以考虑使用ZGC算法(即-XX:+UseZGC)。3.启用GC日志Garbagecollectionlogging包含有关垃圾收集事件,内存回收,暂停持续时间的信息...您可以通过传递以下JVM参数来启用垃圾收集日志:从JDK1到JDK8:-XX:+PrintGCDetails-XX:+PrintGCDateStamps-Xloggc:{file-path}来自JDK9及更高版本:-Xlog:gc*:file={file-path}示例:-XX:+PrintGCDetails-XX:+PrintGCDateStamps-Xloggc:/opt/workspace/myAppgc.log-Xlog:gc*:file=/opt/workspace/myAppgc.log通常GC日志用于调整垃圾收集性能。但是,GC日志包含重要的微观指标。这些指标可用于预测应用程序可用性和性能特征。GC吞吐量是您的应用程序处理客户端事务所花费的时间与其处理GC活动所花费时间的比率。假设您的应用程序的GC吞吐量为98%,这意味着应用程序将其98%的时间用于处理客户端活动,其余2%用于GC活动。现在让我们看一下健康JVM的堆使用图:您可以在图片中看到完美的锯齿模式。您可以注意到,当FullGC(红色三角形)运行时,内存利用率会一直下降到底部。现在让我们看一下有问题的JVM的堆使用图:您可以在图的右端注意到即使GC反复运行,内存利用率也没有下降。这是应用程序遇到某种内存问题的典型迹象。如果您仔细查看该图,您会注意到重复的完整GC在早上8点左右开始发生。但是,应用程序仅在上午8点45分左右才开始抛出OutOfMemoryError。到早上8点,应用程序的GC吞吐量约为99%。但就在早上8点之后,GC吞吐量开始下降到60%。因为应用程序在重复GC运行时不处理任何客户端事务,它只是执行GC活动。作为一种主动措施,如果您注意到GC吞吐量开始下降,您可以从负载均衡器中删除该JVM。这样,不健康的JVM将不会处理任何新流量。它将最大程度地减少对客户的影响。DuplicateFullGChappensbeforeOutOfMemoryError4.-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPathOutOfMemoryError是一个严重的问题,会影响应用程序的可用性/性能SLA。要诊断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获取heapdump后,可以使用HeapHero、EclipseMAT等工具分析heapdump。5.-Xss每个应用都会有几十、几百、几千个线程。每个线程都有自己的栈。每个线程的栈中存储了以下信息:当前执行的方法/函数的返回值原始数据类型变量对象指针。他们每个人都消耗内存。如果它们的消耗超过特定限制,则会抛出StackOverflowError。但是您可以通过传递-Xss参数来增加线程的堆栈大小限制。示例:-Xss256k如果将此-Xss值设置为一个巨大的数字,那么内存将被阻塞和浪费。假设您分配-Xss值为2mb,它只需要256kb,您最终会浪费大量内存,而不仅仅是1792kb(即2mb-256kb)。你想知道为什么吗?假设您的应用程序有500个线程,那么-Xss值为2mb,您的线程将消耗1000mb内存(即500个线程x2mb/线程)。另一方面,如果您只将-Xss分配给256kb,那么您的线程将仅消耗125mb内存(即500个线程x256kb/线程)。您将为每个JVM节省875mb(即1000mb-125mb)的内存。是的,这有很大的不同。我们的建议是从较低的值开始,例如256kb。使用此设置运行彻底的回归、性能和AB测试。只有在遇到StackOverflowError时才增加此值,否则请考虑坚持使用较低的值。6.-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,表示No超时已设置。7.-Duser.timeZone您的应用程序可能有时间/日期敏感的业务需求。例如,如果您正在构建一个交易应用程序,您要到上午9:30才能进行交易。要实现那些与时间/日期相关的业务需求,您可以使用java.util.Date、java.util.Calendar对象。默认情况下,这些对象从底层操作系统获取时区信息。这成为一个问题;如果您的应用程序在分布式环境中运行。考虑以下场景:如果您的应用程序运行在多个数据中心,比如旧金山、芝加哥、新加坡,那么每个数据中心中的JVM将以不同的时区结束。因此,每个数据中心中的JVM将表现不同。这将导致不一致的结果。如果您在云环境中部署应用程序,该应用程序可能会在您不知情的情况下移动到不同的数据中心。同样在这种情况下,您的应用程序最终会产生不同的结果。您自己的运营团队也可以在不通知开发团队的情况下更改时区。它还会扭曲结果。为避免这些混淆,强烈建议使用-Duser.timezone系统属性在JVM上设置时区。例如,如果您想为您的应用程序设置EDT时区,您可以这样做:-Duser.timezone=US/Eastern