【JVM】性能调优

news2025/1/11 0:11:14

图片

一、前言

性能调优,顾名思义,就是对系统或软件的性能进行优化,以提高其运行效率和响应速度。在计算机科学中,性能调优通常涉及到硬件、操作系统、数据库、网络等多个方面。对于Java开发者来说,JVM(Java虚拟机)的性能调优是非常重要的一环,因为JVM的性能直接影响到Java程序的运行效率。

性能调优包含多个层次,比如:架构调优、代码调优、JVM调优、数据库调优、操作系统调优等。架构调优和代码调优是JVM调优的基础,其中架构调优是对系统影响最大的。

图片

性能调优基本上按照以下步骤进行:明确优化目标、发现性能瓶颈、性能调优、通过监控及数据统计工具获得数据、确认是否达到目标。

二、性能定义

要查找和评估器性能瓶颈,首先要知道性能定义,对于jvm调优来说,我们需要知道以下三个定义属性,依作为评估基础:

吞吐量:重要指标之一,是指不考虑垃圾收集引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标。

延迟:其度量标准是缩短由于垃圾啊收集引起的停顿时间或者完全消除因垃圾收集所引起的停顿,避免应用运行时发生抖动。

内存占用:垃圾收集器流畅运行所需要 的内存数量。

这三个属性中,其中一个任何一个属性性能的提高,几乎都是以另外一个或者两个属性性能的损失作代价,不可兼得,具体某一个属性或者两个属性的性能对应用来说比较重要,要基于应用的业务需求来确定。

三、JVM调优的时机

遇到以下情况,就需要考虑进行JVM性能调优:

  1. 程序运行缓慢,响应时间过长;

  2. 程序运行时占用大量内存;

  3. 程序在高并发环境下运行不稳定;

  4. Heap内存(老年代)持续上涨达到设置的最大内存值;

  5. Full GC 次数频繁;

  6. GC 停顿时间过长(超过1秒);

  7. 应用出现OutOfMemory 等内存异常;

  8. 应用中有使用本地缓存且占用大量内存空间;

  9. 系统吞吐量与响应性能不高或下降。

四、调优的基本原则

优先架构调优和代码调优,JVM优化是不得已的手段,大多数的Java应用不需要进行JVM优化。

在调优前,我们需要理解相应原理和掌握技能:

  • 理解JVM的工作原理和架构;

  • 掌握JVM的性能指标和监控工具;

  • 根据实际需求和场景选择合适的JVM参数;

  • 通过实验和数据分析来验证调优效果。

在调优过程中,应该谨记以下3个原则,以便完成垃圾收集的调优,从而达到应用程序的性能要求。

  1. MinorGC回收原则:每次minor GC 都要尽可能多的收集垃圾对象。以减少应用程序发生Full GC的频率。

  2. GC内存最大化原则:处理吞吐量和延迟问题时候,垃圾处理器能使用的内存越大,垃圾收集的效果越好,应用程序也会越来越流畅。

  3. GC调优3选2原则: 在性能属性里面,吞吐量、延迟、内存占用,我们只能选择其中两个进行调优,不可三者兼得。

五、JVM调优目标

JVM调优的主要目标是提高程序的运行效率和响应速度,减少资源消耗,提高系统的稳定性和可扩展性。具体来说,主要包括以下几个方面:

  1. 提高程序的运行速度;

  2. 减少内存消耗;

  3. 减少GC的频率和时间;

  4. 提高系统的吞吐量和并发能力。

吞吐量、延迟、内存占用三者类似CAP,构成了一个不可能三角,只能选择其中两个进行调优,不可三者兼得。

  • 延迟:GC低停顿和GC低频率;

  • 低内存占用;

  • 高吞吐量;

选择了其中两个,必然会会以牺牲另一个为代价。

六、调优工具

常用的JVM调优工具有:

  • JConsole:Java自带的图形化监控工具,可以实时查看JVM的各种性能指标;

  • VisualVM:功能强大的多合一性能分析工具,可以监控多个Java进程,提供详细的性能分析报告;

  • JProfiler:专业的Java性能分析工具,可以深入分析Java代码的执行效率,找出性能瓶颈;

  • Java Mission Control:Oracle推出的新一代Java性能分析工具,可以实时监控和分析Java应用的性能。

  • GCViewer:垃圾回收日志文件分析工具,可以非常直观地分析出待调优点。Memory,分析Totalheap、Tenuredheap、Youngheap内存占用率及其他指标,理论上内存占用率越小越好;Pause,分析Gc pause、Fullgc pause、Total pause三个大项中各指标,理论上GC次数越少越好,GC时长越小越好;

图片

七、JVM调优步骤

JVM调优的基本步骤如下:

  • 分析和定位问题:通过性能监控工具收集数据,分析GC日志及dump文件,分析程序的运行状况,找出性能瓶颈;

  • 选择合适的JVM参数:根据实际需求和场景,确定JVM调优量化目标,调整JVM的内存分配、垃圾回收策略等参数,依次调优内存、延迟、吞吐量等指标;

  • 进行实验和测试:修改JVM参数后,重新运行程序,观察性能变化,验证调优效果;

  • 分析和总结:对比观察调优前后的差异,不断的分析和调整,直到找到合适的JVM参数配置;

以上操作步骤中,某些步骤是需要多次不断迭代完成的。一般是从满足程序的内存使用需求开始的,之后是时间延迟的要求,最后才是吞吐量的要求,要基于这个步骤来不断优化,每一个步骤都是进行下一步的基础,不可逆行。

图片

八、JVM参数

JVM调优涉及的参数非常多,以下是一些常用的参数:

  1. -Xms:设置堆初始大小;

  2. -Xmx:设置堆最大大小;

  3. -Xmn:设置新生代大小;

  4. -XX:NewRatio:设置新生代与老年代的比例;

  5. -XX:SurvivorRatio:设置Eden区与Survivor区的比例;

  6. -XX:+UseParallelGC:选择并行垃圾回收器;

  7. -XX:+UseConcMarkSweepGC:选择CMS垃圾回收器;

  8. -XX:+UseG1GC:选择G1垃圾回收器;

  9. -XX:MaxGCPauseMillis:设置最大暂停时间目标;

  10. -XX:InitiatingHeapOccupancyPercent:设置触发Full GC的老年代占用率阈值。

图片

运行时JIT编译器优化参数

JIT编译指的是字节码编译为本地代码(汇编)执行,只有热点代码才会编译为本地代码。解释器执行节约内存,反之可以使用编译执行来提升效率。

图片

实用代码示例

示例1:设置和监控堆内存大小

JVM启动参数:

java -Xms512m -Xmx2g -jar YourApp.jar
  • -Xms512m:设置初始堆内存为512MB。

  • -Xmx2g:设置最大堆内存为2GB。


public class HeapSizeMonitoring {
    public static void main(String[] args) {
        // 获取运行时环境
        Runtime runtime = Runtime.getRuntime();

        // 打印JVM的初始内存和最大内存配置
        System.out.println("JVM初始内存大小:" + runtime.totalMemory() / (1024 * 1024) + " MB");
        System.out.println("JVM最大内存大小:" + runtime.maxMemory() / (1024 * 1024) + " MB");
    }
}

示例2:使用G1垃圾收集器并监控GC

JVM启动参数:

java -XX:+UseG1GC -XX:MaxGCPauseMillis=300 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar YourApp.jar
  • -XX:+UseG1GC:使用G1垃圾收集器。

  • -XX:MaxGCPauseMillis=200:设置期望的最大GC暂停时间为300毫秒。

  • -XX:+PrintGCDetails 和 -XX:+PrintGCDateStamps:打印GC的详细信息和时间戳。

示例3:线程堆栈大小的设置与监控

JVM启动参数:

java -Xss512k -jar YourApp.jar
  • -Xss512k:设置每个线程的堆栈大小为512KB。

示例4:使用G1垃圾收集器并调优

JVM启动参数:

java -XX:+UseG1GC -XX:MaxGCPauseMillis=300 -XX:InitiatingHeapOccupancyPercent=50 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar YourApp.jar
  • -XX:+UseG1GC:使用G1垃圾收集器。

  • -XX:MaxGCPauseMillis=300:尝试将GC的最大暂停时间控制在300毫秒以内。

  • -XX:InitiatingHeapOccupancyPercent=50:当堆占用率达到50%时开始GC。

  • -XX:+PrintGCDetails 和 -XX:+PrintGCDateStamps:打印详细的GC信息和时间戳。

示例5:监控垃圾收集信息

JVM启动参数:

java -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar YourApp.jar
  • -XX:+PrintGC:打印基本的GC信息。

  • -XX:+PrintGCDetails:打印GC的详细信息。

  • -XX:+PrintGCDateStamps:在GC日志中加入时间戳。

示例6:设置线程堆栈大小

JVM启动参数:

java -Xss1024k -jar YourApp.jar
  • -Xss1024k:设置每个线程的堆栈大小为1024KB。

示例7:监控类的加载和卸载

JVM启动参数:

java -XX:+TraceClassLoading -XX:+TraceClassUnloading -jar YourApp.jar
  • -XX:+TraceClassLoading:启用类加载跟踪。

  • -XX:+TraceClassUnloading:启用类卸载跟踪。

示例8:监控垃圾回收行为

JVM启动参数:

java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log -jar YourApp.jar
  • -XX:+PrintGCDetails:打印垃圾回收的详细信息。

  • -XX:+PrintGCDateStamps:在垃圾回收日志中加入时间戳。

  • -Xloggc:gc.log:将垃圾回收日志记录到指定文件。

示例9:配置和使用字符串去重功能

JVM启动参数:

java -XX:+UseStringDeduplication -XX:+PrintStringDeduplicationStatistics -jar YourApp.jar
  • -XX:+UseStringDeduplication:开启JVM的字符串去重功能。

  • -XX:+PrintStringDeduplicationStatistics:打印字符串去重的统计信息。

示例10:使用并行垃圾收集器

JVM启动参数:

java -XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:+PrintGCDetails -jar YourApp.jar
  • -XX:+UseParallelGC:使用并行垃圾收集器。

  • -XX:GCTimeRatio=4:设置吞吐量目标,表示99%的时间用于应用程序,1%的时间用于垃圾收集。

  • -XX:+PrintGCDetails:打印垃圾收集的详细信息。

示例11:设置和监控ZGC垃圾收集器

JVM启动参数:

java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc -jar YourApp.jar
  • -XX:+UnlockExperimentalVMOptions:解锁实验性VM选项。

  • -XX:+UseZGC:使用ZGC垃圾收集器。

  • -Xlog:gc:开启GC日志。

九、结语

合理的JVM调优可以显著提升应用的性能和稳定性。不过,请记得调优是一个持续的过程,需要根据应用的具体表现来不断调整和优化。

最后由于版本不断更新,JVM参数和具体说明,建议需要时请参考 oracle 官网的手册。

图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1393625.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

centos7 arm服务器编译升级安装动态库libstdc++.so.6,解决GLIBC和CXXABI版本低的问题

前言 由于centos7内置的libstdc.so.6版本太低,导致安装第三方包的时候,会报“CXXABI_1.3.8”不存在等问题。 自带的打印如下: strings /usr/lib64/libstdc.so.6 | grep GLIBC strings /usr/lib64/libstdc.so.6 | grep CXXABI 如图 升级 注…

RK3399平台入门到精通系列讲解(USB篇)UDC 层 usb_gadget_probe_driver 接口分析

🚀返回总目录 文章目录 一、UDC:usb_gadget_probe_driver函数分析二、usb_gadget_driver 结构详细介绍三、usb_udc 结构详细介绍一、UDC:usb_gadget_probe_driver函数分析 UDC层的一项基本任务是向上层提供usb_gadget_probe_driver()接口函数。 上层调用者为composite.c中…

【征服redis7】谈谈Redis的RDB持久化方式

从现在开始,我们来探讨redis的一个非常重要的问题——集群,要讨论集群,我们需要先理解redis持久化数据的方法,因为集群本质上就是将一个集群的数据同步到其他机器上。 Redis 6的持久化机制主要有两种:RDB(…

WordPress回收站自动清空时间?如何关闭回收站或设置自动清理天数?

我们在WordPress后台的文章、页面、评论等页面都可以看到有回收站,意思就是我们不能直接删除某篇文章、页面、评论,而是需要现将它们移至回收站,然后再到回收站永久删除,或等回收站自动清理。 如上图所示,WordPress 6.…

Django笔记(一):环境部署

目录 Python虚拟环境 安装virtualenv 创建环境 激活环境 关闭: 安装Django VSCode配置 Python插件 Django插件 解释器选择 Django部署 创建项目 创建app 创建模板 编写视图 编写路由 启动服务器 访问 Python虚拟环境 安装virtualenv pip i…

H5小游戏如何提升APP变现收益?

在当前用户规模稳定但变现压力增加的背景下,开发者需要挖掘用户价值,提高营收,这成为开发者关注的重点话题。对于那些“用户用完即走”的APP产品来说,接入H5游戏能够吸引停留,为其带来收入上的增长。 一、什么是H5游戏…

面经-redis缓存

什么是Redis Redis(Remote Dictionary Server)键只能为字符串,值:字符串、列表、集合、散列表、有序集合。Redis 用来做分布式锁。支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。 Redis为什么这么快 完全基于内存,数据结构简单…

如何在CentOS下使用Docker部署Halo博客网站并结合内网穿透远程访问

文章目录 ⛳️ 推荐1. Docker部署Halo1.1 检查Docker版本如果未安装Docker可参考已安装Docker步骤:1.2 在Docker中部署Halo 2. Linux安装Cpolar2.1 打开服务器防火墙2.2 安装cpolar内网穿透 3. 配置Halo个人博客公网地址4. 固定Halo公网地址 ⛳️ 推荐 前些天发现了…

selenium-java中切换iframe

1、当iframe中有固定的name或者id时可以通过name和id进行切换,代码如下 driver.switchTo().frame("name"); 2、当iframe中没有固定的name或者id时可以通过iframe角标进行切换,在浏览器通过ctrlf快捷键,搜索标签框输入//iframe;来查看当前ifr…

web开发学习笔记(9.Tomcat介绍)

1.简介 2.tomcat和nginx等web应用服务器的区别 http://t.csdnimg.cn/OL9Qt 3.tomcat基本使用 4.tomcat更改端口号 5. 部署

三大爆款婴儿洗衣机深度测评,希亦、小吉、鲸立哪款最值得入手?

婴儿洗衣机,顾名思义就是专门给婴儿使用的洗衣机,它的功能更加有针对性,同时设计上也有普通洗衣机不同。对于不少有工作的宝爸宝妈而言,在日常生活中并没有充足的时间可以给孩子洗衣物,婴儿洗衣机是非常有必要买的。而…

使用freessl为网站获取https证书及配置详细步骤

文章目录 一、进入freessl网站二、修改域名解析记录三、创建证书四、配置证书五、服务启动 一、进入freessl网站 首先进入freessl网站,需要注册一个账号 freessl网站 进入网站后填写自己的域名 接下来要求进行DCV配置 二、修改域名解析记录 到域名管理处编辑域名…

服务器——Vscode选择虚拟环境编译器后,无法跳转至对应的python路径的解决办法

一、现象 输入 which python,显示 /bin/python,而不是对应的python路径。 二、原因分析 该用户账户下的.bashrc文件手动指定了python路径。 三、解决办法 将手动指定的python路径代码注释,这样就跟随编译器,自动选择python路…

k8s---对外服务 ingress

目录 目录 目录 ingress与service ingress的组成 ingress-controller: ingress暴露服务的方式 2.方式二:DaemonSethostnetworknodeSelector DaemonSethostnetworknodeSelector如何实现 3.deploymentNodePort: 虚拟主机的方式实现http代…

戴森持续深耕室内空气质量研究,携手商业空间打造全场景的洁净呼吸新体验

[2024年 1 月 18 日, 中国上海] 随着气温的日渐下降,家人陪伴和好友相聚也逐渐回归室内。和三两好友一起动手做些烘焙美食,相约美术馆看展,或室内亲子乐园成为不少家庭冬日生活的新风尚。为了进一步洞察消费者生活方式背后对于健康呼吸的多样…

Mybatis----面向接口

让mybatis自动生成dao层接口的实现类 这是dao层接口的实现类,在mybatis中我们可以省略这种实现接口的方式,直接面向接口操作数据库,mybatis可以帮我们自动生成接口的实现类,也就是下面这个实现类mybatis帮我们生成了。 1、修改se…

鸿蒙开发之状态管理

State 组件内状态 State装饰的变量,会和自定义组件的渲染绑定起来。当状态改变时,UI会发生对应的渲染改变。在状态变量相关装饰器中,State是最基础的,使变量拥有状态属性的装饰器,它也是大部分状态变量的数据源。 装…

数据库事务隔离级别的总结

一、数据库四种隔离级别 RU(READ-UNCOMMITTED) 读取事务未提交的数据。RC(READ-COMMITTED) 读取到事务已提交的数据。RR(REPEATABLE-READ) 可重复读SR(SERIALIZABLE) 串行化 二、四…

chisel入门初步1——基4的booth编码的单周期有符号乘法器实现

基4的booth编码乘法器原理说明 基2的booth编码 本质来说就是一个裂项重组,乘法器最重要的设计是改变部分积的数量,另外在考虑有符号数的情况下,最高位符号位有特别的意义。 (注:部分积是指需要最后一起加和的所有部分…

Qt6入门教程 8:信号和槽机制(连接方式)

目录 一.一个信号与槽连接的例子 二.第五个参数 1.Qt::AutoConnection 2.Qt::DirectConnection 3.Qt::QueuedConnection 4.Qt::BlockingQueuedConnection 5.Qt::UniqueConnection 三.信号 四.connect函数原型 五.信号与槽的多种用法 六.槽的属性 一.一个信号与槽连接…