【Java虚拟机】JVM调优和分析案例综合实战

news2025/2/23 23:38:08

1.什么是JVM性能优化

jvm性能优化涉及到两个很重要的概念:吞吐量和响应时间。jvm调优主要是针对他们进行调整优化,达到一个理想的目标,根据业务确定目标是吞吐量优先还是响应时间优先。

  • 吞吐量:用户代码执行时间/(用户代码执行时间+GC执行时间)。
  • 响应时间:整个接口的响应时间(用户代码执行时间+GC执行时间),STW时间越短,响应时间越短。

调优方法论

  • 监控JVM性能

    • 对JVM的运行情况进行监控,以了解应用程序的瓶颈和性能瓶颈
    • 可以使用JVM自带的工具,如jstat、jmap、jstack等,或者第三方工具,如VisualVM、JProfiler等
  • 压测基准指标

    • 对程序进行压测,得出接口对应的吞吐量、响应时间等
    • 外部现象
      • 对用户体验来说,就是响应速度
      • 可以用压测工具jmeter进行压测得出相关性能指标
    • 内部现象:
      • 分析GC情况,是JVM性能调优的重要因素,需要掌握GC的工作机制和GC日志的含义
      • 可以使用JVM自带的GC日志或者第三方工具,如GCEasy等来分析GC情况,了解GC的频率、时间、内存占用等情况
  • 调整JVM参数

    • 通过调整堆大小、GC算法、线程池大小等参数来提高应用程序的性能
    • 注意:不同的应用程序和环境可能需要不同的JVM参数配置,比如IO密集型和CPU密集型应用
  • 二次压测分析

    • 通过调整jvm参数后,二次压测看性能指标提升还是下降
    • 内部:GC日志,看吞吐量,GC次数,停顿时间变化
    • 外部:接口对应的吞吐量、响应时间是否更优
  • 其他优化方式

    • 优化代码

      • 通过避免不必要的对象创建、减少同步操作、使用缓存等方式来优化代码。
      • 注意:代码优化应该遵循“先正确,再优化”的原则,不应该牺牲代码的可读性和可维护性
    • 使用并发编程

      • 使用多线程、线程池等方式来提高并发性能,比如调整线程池的队列长度,存活线程数量等
      • 注意:并发编程需要考虑线程安全和锁竞争等问题,需要进行正确的设计和实现
    • 使用缓存

      • 可以使用本地缓存、分布式缓存等方式来提高数据访问性能
      • 注意:缓存需要考虑缓存一致性和缓存失效等问题,需要进行正确的设计和实现
    • 避免IO阻塞

      • 使用异步IO、NIO等方式来提高IO性能,比如前面学的CompletableFuture异步任务编排
      • 注意:IO编程需要考虑并发性和可靠性等问题,需要进行正确的设计和实现
    • 分布式+集群技术

      • 使用负载均衡+集群技术,提升单节点的处理能力

2.JVM调优之压测环境准备

  • SpringBoot 编写的jar的程序,接口一个返回随机组成的100个以内的对象的list (使用JDK17)
/**
 * @author lixiang
 * @date 2023/5/8 21:44
 */
@Slf4j
@RestController
@RequestMapping("/spring-test")
public class SpringTestController {

    @RequestMapping("query")
    public Map<String, Object> query() throws InterruptedException {

        int num = (int) (Math.random() * 100) + 1;
        //申请5MB内存
        Byte[] bytes = new Byte[5 * 1024 * 1024];

        List<Product> productList = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Product product = new Product();
            product.setPrice((int) Math.random() * 100);
            product.setTitle("商品编号" + i);
            productList.add(product);
        }

        Thread.sleep(5);
        Map<String, Object> map = new HashMap<>(16);
        map.put("data", productList);
        return map;

    }

}
  • Jmeter压测工具准备,测试计划 200并发,循环500次

3.JVM性能优化之堆大小配置

  • 堆大小配置,FullGC次数的性能影响
  • 性能优化初始值
-Xms1g # 配置初始堆内存1G
-Xmx1g # 配置最大堆内存1G
-XX:+UseG1GC # 使用G1回收器
-XX:MaxGCPauseMillis=200 # 设置最大停顿时间200ms
-XX:G1HeapRegionSize=32M # 设置G1每个region块大小为32M
-XX:ActiveProcessorCount=8 # 设置JVM使用的CPU核数限制为8
-XX:+HeapDumpOnOutOfMemoryError # 当JVM发生OOM时,自动生成DUMP文件
-XX:HeapDumpPath=heapdump.hprof # DUMP文件路径
-XX:+PrintCommandLineFlags # 监控开启
-Xlog:gc=info:file=portal_gc.log:utctime,level,tags:filecount=50,filesize=100M 
  # Xlog:指定日志输出方式为日志文件。
  # gc*:指定日志输出类型为GC相关的日志。
  # info:指定输出日志的级别为info级别。
  # file=portal_gc.log:指定日志输出的文件名为portal_gc.log。
  # utctime:指定日志输出的时间戳使用UTC时间。
  # level,tags:指定日志输出的格式包含级别和标签信息。
  # filecount=50:指定最多保存50个日志文件。
  # filesize=100M:指定每个日志文件的大小为100MB。
  • 机器配置为:8核16G 500M带宽

在这里插入图片描述

  • 设置初始堆内存和最大堆内存为1G,压测
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms1g -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

在这里插入图片描述在这里插入图片描述

当我们设置堆内存为1G的时候,整体的吞吐量为40%以上,这已经很低了,期间Young GC发生了7451次,Full GC发生了142次

  • 设置初始堆内存和最大堆内存为2G,压测
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms2g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

在这里插入图片描述在这里插入图片描述

我们将堆内存设置为2G的时候,相比于1G的吞吐量提升到70%以上,并且Young GC次数为752,Full GC次数为6次,相比1G提升了一倍。

  • 设置初始堆内存和最大堆内存为4G,压测
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

在这里插入图片描述在这里插入图片描述

当把堆内存设置为4G的时候,整体的吞吐量提升到76%,Young GC发生了504,一次Full GC都没有发生。

  • 设置初始堆内存和最大堆内存为6G,压测
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms6g -Xmx6g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

在这里插入图片描述在这里插入图片描述

当把堆内存设置为6G的时候,整体吞吐量到达87%,Yong GC发生了196次,Full GC发生了0次。

总结:通过对堆内存的调整,发现4G是投入产出比最高的参数配置,所以当前配置可以采用4G的堆内存。

4.JVM性能优化之收集器配置

通过上面配置堆内存我们得出4G是当前机器和应用配置的最佳堆内存,这里我们不改变堆内存的大小,采用4G的堆内存,改变垃圾收集器,看看对接口吞吐量的影响。

这里我们采用ParallelGC,目前G1垃圾器在对于并发量大的应用来说,已经是最优的选择啦,我们这里用ParallelGC主要做一个对比。

nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms4g -Xmx4g -XX:+UseParallelGC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

C语言学习分享(第六次)------数组

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C语言学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C语言知识   &#x1f51d;&#x1f51d; 数组详解 1. 前言&#x1f536;2. …

使用 spring 的 IoC 的实现账户的CRUD(2)双层实现

spring实现service和dao的数据的查找 dao层设置接口实现dao层的接口service设置接口通过注入dao层&#xff0c;来实现接口 //dao层的接口&#xff0c;定义了根据id查询的方法 public interface Accountdao {Account findByid(int id); }实现接口&#xff1a;实现了查询的方法 …

【模板】拓扑排序

import java.util.Scanner; import java.util.*;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);int point in.nextInt();int side in.nextInt();int[][] arr new i…

MacOS下安装和配置Nginx

一、安装brew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"按回车后&#xff0c;根据提示操作&#xff1a;输入镜像序号 --> 输入Y&#xff0c;回车等待brew安装完成即可。 在终端输入brew -v后&#xff0c;会提示…

【牛客刷题专栏】0x25:JZ24 反转链表(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录 前言问…

Jedis客户端和SpringDataRedis客户端

目录 3.Redis的Java客户端 3.1.Jedis客户端 3.1.1.快速入门 3.1.2.连接池 3.2.SpringDataRedis客户端 3.2.1.快速入门 3.2.2.自定义序列化 3.2.3.StringRedisTemplate 3.Redis的Java客户端 3.1.Jedis客户端 Jedis的官网地址&#xff1a; GitHub - redis/jedis: Redis…

单片机中时钟分析与快速读懂时序图的方法

目录 一、时钟电路 二、周期 三、时序 我们都知道在学校是通过铃声来控制所有班级的上下课时间&#xff0c;那个单片机是通过什么样的办法进行取指令&#xff0c;执行指令和其它操作的呢&#xff1f;在这里引入了一个时序的概念。 一、时钟电路 单片机时钟电路有三种方式…

LoadRunner的简单使用

目录 1、LoadRunner工具介绍 2、VUG的使用 3、Controller的使用 3.1、场景设计 3.2、场景运行及结果 4、Analysis的使用 1、LoadRunner工具介绍 Virtual User Generator&#xff1a;主要用来生成性能测试脚本Controller&#xff1a;创建测试场景&#xff0c;运行测试脚本、…

民用电力远程监控解决方案

民用电力远程监控解决方案 项目背景 随着我国城市现代化的飞速发展&#xff0c;城市配电系统的不断改造更新&#xff0c;信息化、网络化和智能化的快速发展&#xff0c;要求箱变安全稳定运行&#xff0c;出现故障能够及时排除保证快速供电。 但是&#xff0c;电力行业的监控…

如何挖掘闲置硬件资源的潜力-PrestoDB缓存加速实践小结

用户体验的追求是无限的&#xff0c;而成本是有限的&#xff0c;如何平衡&#xff1f; 用户体验很重要&#xff0c;降本也很重要。做技术的都知道&#xff0c;加机器堆资源可以解决绝大多数的用户觉得慢的问题&#xff0c;但要加钱。没什么用户体验是开发不了的&#xff0c;但…

阿里高P谈内卷,基础牢固才能破局,你的技术栈深度跟广度真的够么?

​ ​ 最近内卷严重&#xff0c;各种跳槽裁员&#xff0c;分享一套学习笔记 / 面试手册&#xff0c;准备跳槽的朋友可以好好刷一刷&#xff0c;还是挺有必要的&#xff0c;它几乎涵盖了所有的软件测试技术栈&#xff0c;非常珍贵&#xff0c;肝完进大厂&#xff01;妥妥的。相信…

PID算法(位置式pid算法和增量式pid算法)

这里写目录标题 PID算法介绍比例环节比例积分环节比例积分微分环节 位置式PID增量式PIDPID参数整定采样周期选择PID参数整定方法![请添加图片描述](https://img-blog.csdnimg.cn/849bf1672243484699b131b487f05a55.png)试凑法临界比例法一般调节法 PID算法介绍 PID 算法是闭环…

使用Process Monitor探测Windows系统高DPI缩放设置的注册表项

目录 1、在高显示比例下部分软件界面显示模糊问题 2、如何设置才能使得软件显示的清晰一些&#xff1f; 3、使用Process Monitor监测上述设置对应的注册表的操作 4、最后 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff…

分布式 04 nginx 的使用

01.Nginx可以理解成为一个代理运营商在计算机网络中。用户发送的请求在Nginx中处理&#xff0c;而后分配给相关的服务器 02.在Nginx文件中conf文件件&#xff0c;中修改nginx.conf文件 首先先去监听和获取请求&#xff0c;使用关键字server 这个是浏览器url中输入localhost时…

如何在本地部署运行ChatGLM-6B

在本篇技术博客中&#xff0c;将展示如何在本地获取运行代码和模型&#xff0c;并配置环境以及 Web GUI&#xff0c;最后通过 Gradio 的网页版 Demo 进行聊天。 官方介绍 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM)…

Flutter 自定义裁剪之圆形豁口/缺口

目录 Flutter自定义裁剪Flutter的自定义裁剪类CustomClipper裁剪的实际代码思路分析注意点完整代码总结如图所示,图中的圆形缺口,需要我们自定义裁剪,才能实现。 Flutter自定义裁剪 裁剪,我们想到的是剪刀,实际上,Flutter的裁剪原理,和我们现实物理世界的剪刀是一样的…

木夕的IC日记——Vim使用【一】

Vim使用日记【一】 Vim的运行方式进入Vim第一步&#xff1a;打开文件保存文件并退出Vim三种模式下能做哪些事命令模式编辑模式底行模式Visual Block功能 Vim的运行方式 作为Linux系统中最常用的文本编辑器&#xff0c;Vim体现了Linux“万物皆是文件”的设计哲学。通过Vim&…

flink集群安装部署

1.下载 官网下载&#xff1a;Downloads | Apache Flink 阿里网盘下载&#xff08;包含依赖包&#xff09;&#xff1a;阿里云盘分享 提取码&#xff1a;9bl2 2.解压 tar -zxvf flink-1.12.7-bin-scala_2.11.tgz -C ../opt/module 3.修改配置文件 cd flink-1.12.7/conf/ …

[C++]string的使用

目录 string的使用&#xff1a;&#xff1a; 1.string类介绍 2.string常用接口说明 string相关习题训练&#xff1a;&#xff1a; 1.仅仅反转字母 2.找字符串中第一个只出现一次的字符 3.字符串里面最后一个单词的长度 4.验证一个字符串是否是回文 5.字符串相加 6.翻转字符串…

[Dubbo] 重要接口与类 (三)

文章目录 1.dubbo的整体调用链路2.dubbo的源码整体设计3.重要接口和类 1.dubbo的整体调用链路 消费者通过Interface进行方法调用&#xff0c;统一交由消费者的Proxy处理&#xff08;Proxy通过ProxyFactory来进行代理对象的创建&#xff09; Proxy调用Filter模块&#xff0c;做…