性能调优

news/2024/11/15 1:56:15/

性能调优

应用程序在运行过程中经常会出现性能问题,比较常见的性能问题现象是:

  • 通过top命令查看CPU占用率高,接近100甚至多核CPU下超过100都是有可能的。
  • 请求单个服务处理时间特别长,多服务使用skywalking等监控系统来判断是哪一个环节性能低下。
  • 程序启动之后运行正常,但是在运行一段时间之后无法处理任何的请求(内存和GC正常)。

线程转储

线程转储(Thread Dump)提供了对所有运行中的线程当前状态的快照。线程转储可以通过jstack、visualvm等工具获取。其中包含了线程名、优先级、线程ID、线程状态、线程栈信息等等内容,可以用来解决CPU占用率高、死锁等问题

线程转储(Thread Dump)中的几个核心内容:

  • 名称:线程名称,通过给线程设置合适的名称更容易“见名知意”
  • 优先级(prio):线程的优先级
  • Java ID(tid):JVM中线程的唯一ID
  • 本地 ID (nid):操作系统分配给线程的唯一ID
  • 状态:线程的状态,分为: NEW – 新创建的线程,尚未开始执行 RUNNABLE –正在运行或准备执行 BLOCKED – 等待获取监视器锁以进入或重新进入同步块/方法 WAITING – 等待其他线程执行特定操作,没有时间限制 TIMED_WAITING – 等待其他线程在指定时间内执行特定操作 TERMINATED – 已完成执行
  • 栈追踪: 显示整个方法的栈帧信息

线程转储的可视化在线分析平台:https://fastthread.io/ (需要科学上网)

请添加图片描述

CPU占用率高问题的解决方案

1)通过top –c 命令找到CPU占用率高的进程,获取它的进程ID。

2)使用top -p 进程ID单独监控某个进程,按H可以查看到所有的线程以及线程对应 的CPU使用率,找到CPU使用率特别高的线程。

3)使用 jstack 进程ID命令可以查看到所有线程正在执行的栈信息。使用 jstack进程ID > 文件名 保存到文件中方便查看。

4)找到nid线程ID相同的栈信息,需要将之前记录下的十进制线程号转换成16进制 。通过 printf ‘%x\n’ 线程ID 命令直接获得16进制下的线程ID。

请添加图片描述

5)找到栈信息对应的源代码,并分析问题产生原因。

接口响应时间长的问题

已经确定是某个接口性能出现了问题,但是由于方法嵌套比较深,需要借助于arthas定位到具体的方法。

使用arthas的trace命令,可以展示出整个方法的调用路径以及每一个方法的执行耗时。

命令:trace 类名 方法名

  • 添加 --skipJDKMethod false 参数可以输出JDK核心包中的方法及耗时。
  • 添加 ‘#cost > 毫秒值’ 参数,只会显示耗时超过该毫秒值的调用。
  • 添加 –n 数值 参数,最多显示该数值条数的数据。
  • 所有监控都结束之后,输入stop结束监控,重置arthas增强的对象。

在使用trace定位到性能较低的方法之后,使用watch命令监控该方法,可以获得更为详细的方法信息。

命令: watch 类名 方法名 ‘{params, returnObj}’ ‘#cost>毫秒值' -x 2

  • ‘{params, returnObj}‘ 代表打印参数和返回值。
  • -x 代表打印的结果中如果有嵌套(比如对象里有属性),最多只展开2层。允许设置的最大值为4。

最后记得使用stop命令将所有增强的对象恢复。

JMH

OpenJDK中提供了一款叫JMH(Java Microbenchmark Harness)的工具,可以准确地对Java代码进行基准测试, 量化方法的执行性能。

JMH会首先执行预热过程,确保JIT对代码进行优化之后再进行真正的迭代测试,最后输出测试的结果。

1)引入依赖

<dependencies><dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-core</artifactId><version>1.33</version> <!-- 使用最新的版本 --></dependency><dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-generator-annprocess</artifactId><version>1.33</version> <!-- 使用最新的版本 --></dependency>
</dependencies>

2)编写测试代码

java">package cn.ehang;import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;import java.util.concurrent.TimeUnit;@BenchmarkMode(Mode.AverageTime)
@State(Scope.Thread)
@Fork(1)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 3)
@Measurement(iterations = 5)
public class Main {String string = "";StringBuilder stringBuilder = new StringBuilder();@Benchmarkpublic String stringAdd() {for (int i = 0; i < 1000; i++) {string = string + i;}return string;}@Benchmarkpublic String stringBuilderAppend() {for (int i = 0; i < 1000; i++) {stringBuilder.append(i);}return stringBuilder.toString();}public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(Main.class.getSimpleName()).build();new Runner(opt).run();}
}

3)测试结果

# JMH version: 1.33
# VM version: JDK 17.0.11, Java HotSpot(TM) 64-Bit Server VM, 17.0.11+7-LTS-207
# VM invoker: C:\Program Files\Java\jdk-17\bin\java.exe
# VM options: -Dvisualvm.id=11302190666600 -javaagent:D:\software\IntelliJ IDEA 2024.1.4\lib\idea_rt.jar=50868:D:\software\IntelliJ IDEA 2024.1.4\bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint (default, use -Djmh.blackhole.autoDetect=true to auto-detect)
# Warmup: 3 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: cn.ehang.Main.stringAdd# Run progress: 0.00% complete, ETA 00:02:40
# Fork: 1 of 1
# Warmup Iteration   1: 26.184 ms/op
# Warmup Iteration   2: 60.169 ms/op
# Warmup Iteration   3: 80.841 ms/op
Iteration   1: 103.935 ms/op
Iteration   2: 122.784 ms/op
Iteration   3: 135.320 ms/op
Iteration   4: 147.907 ms/op
Iteration   5: 160.549 ms/opResult "cn.ehang.Main.stringAdd":134.099 ±(99.9%) 84.575 ms/op [Average](min, avg, max) = (103.935, 134.099, 160.549), stdev = 21.964CI (99.9%): [49.524, 218.674] (assumes normal distribution)

http://www.ppmy.cn/news/1528351.html

相关文章

50.面向对象进阶训练-学生类

//定义一个长度为3的数组&#xff0c;存储1-3名学生对象作为初始数据 //学生属性&#xff1a;学号 姓名 年龄&#xff0c;其中学号姓名各不相同 //要求&#xff1a;1.再次添加一个学生对象&#xff0c;并在添加的时候进行学号的唯一性判断//2.添加完毕之后&#xff0c;遍历所有…

第4步CentOS配置SSH服务用SSH终端XShell等连接方便文件上传或其它操作

宿主机的VM安装CENTOS文件无法快速上传&#xff0c;也不方便输入命令行&#xff0c;用SSH终端xshell连接虚拟机的SSH工具就方便多了&#xff0c;实现VM所在宿主机Win10上的xshell能连接vm的centos要实现以下几个环节 1、确保宿主机与虚拟机的连通性。 2、虚拟机安装SSH服务&…

金属材质检测系统源码分享

金属材质检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

从 “Hello, World!“ 到深入理解 print 函数与异常类型

一、Hello, World!&#xff1a;Python 编程的入门仪式 当我们开始学习任何一门编程语言时&#xff0c;几乎都会先接触到 "Hello, World!" 程序。它就像是一扇通往编程世界的大门&#xff0c;简单却意义非凡。在 Python 中&#xff0c;实现这个程序只需要一行代码&…

个人小结(2.0)

离谱&#xff0c;困扰着几周的问题今天偶然发现了解决方法。 问题如下&#xff1a;就是对应的模块引入爆红&#xff0c;但是单击进入引入的文件没有问题 然后它的提示是&#xff1a; 无法找到模块“../views/screen/index.vue”的声明文件。“c:/Users/10834/Desktop/0716_pro…

uniapp微信小程序用户授权方法

效果 步骤 1&#xff09;div标签 <button type"primary" class"btn-login" click"getUserInfo">一键登录</button>2&#xff09;js方法 methods: {getUserInfo() {console.log("aaaa")uni.getUserProfile({desc: Wexin, …

MATLAB基础:7.计算与编程策略

计算与编程策略 一、矢量化编程 MATLAB以矩阵为基本元素 什么是矢量化编程 将矩阵视为一个整体&#xff0c;对矩阵中的元素同时进行某种操作或运算&#xff0c;即整块的操作大量数据 矢量化编程的优点 代码大大简化&#xff0c;编程效率高&#xff0c;代码可读性高程序执行…

npm的作用域介绍

npm 的作用域 在 node_modules 目录中&#xff0c;带有 符号的目录和不带 符号的目录有以下区别&#xff1a; 带 的目录&#xff1a; 表示这是一个 作用域&#xff08;Scoped Package&#xff09;。作用域可以帮助组织和管理相关的包&#xff0c;通常以 scope/package-na…