JVM内存分析工具-Arthas 教程[详细]
一、概述
Arthas(阿尔萨斯)是阿里巴巴开源的一款Java诊断工具,用于实时检测、诊断Java应用程序的性能问题。它是一个命令行工具,提供了丰富的功能,包括查看类加载信息、方法执行耗时、线程堆栈、内存分析等。Arthas 的设计目标是在生产环境中实时诊断和解决Java应用程序的问题。
以下是 Arthas 的一些主要特点和功能:
- 实时性: Arthas 可以在运行中的 Java 进程中实时进行诊断,无需重新启动应用。
- 丰富的命令: 提供了众多的命令,涵盖了类加载、方法执行、线程、内存、GC 等多个方面。
- 动态追踪: 支持实时动态追踪方法调用、线程堆栈等信息,方便定位问题。
- 内存分析: 提供了 Heap Dump、Histogram、Classloader Stats 等命令,帮助进行内存分析。
- 多种环境支持: 支持 Linux、Mac 和 Windows 操作系统,支持 HotSpot 和 OpenJ9 JVM。
- 在线帮助: 提供了丰富的在线帮助,用户可以通过 help 命令查看每个命令的详细说明。
请注意,Arthas 的使用可能需要一些对 Java 应用程序的基本了解。在生产环境中使用 Arthas 时,需要谨慎操作,以免对应用程序产生影响。详细的使用方法和命令说明可以参考 Arthas 的官方文档:
- https://arthas.aliyun.com/doc/
- https://github.com/alibaba/arthas。
二、Arthas 安装
全量安装
wget https://arthas.aliyun.com/download/latest_version?mirror=aliyun -O arthas-packaging-3.7.1-bin.zipunzip arthas-packaging-3.7.1-bin.zip
三、Arthas 主要组成结构
主要有以下几大组件:
- arthas-core.jar 是服务器端的启动入口类,调用 VirtualMachine#attach 到目标进程,并加载 arthas-agent.jar 作为 agent 包。
- arthas-agent.jar 既可以使用 premain 方式(在目标进程启动之前,通过-agent参数静态指定),也可以通过 agentmain 方式(在进程启动之后attach上去)。arthas-agent会使用自定义的classloader(ArthasClassLoader)加载arthas-core.jar里面的Configure类以及ArthasBootstrap。 同时程序运行的时候会使用arthas-spy.jar。
- arthas-spy.jar 里面只包含Spy类,目的是为了将Spy类使用BootstrapClassLoader来加载,从而使目标进程的java应用可以访问Spy类。通过ASM修改字节码,可以将Spy类的方法ON_BEFORE_METHOD, ON_RETURN_METHOD等编织到目标类里面。
- arthas-client.jar 是客户端程序,用来连接arthas-core.jar启动的服务端代码,使用telnet方式。一般由arthas-boot.jar和as.sh来负责启动。
四、Arthas 通信主要流程
Arthas 应用是基于C/S的通信架构来设计的,支持 Telnet 和 Http 的客户端协议通信。
- 在服务器端的启动过程中会调用 ArthasBootstrap#bind 中, 会启动 Telnet 和 Http 通信协议的服务器实例并接收请求。
- 服务器端接收到客户端连接后都会为每个连接生成会话窗口,并会将发过来的请求内容解析后生成命令交由任务控制去完成响应。
- 其中每个客户端通信都对应唯一的 ShellImpl 实现,里面包括了唯一的Session 实例,并持有JobControllerImpl 和 InternalCommandManager 对象用于组装出异步任务去执行这个命令。
- InternalCommandManager 类记录了所有命令,通过名字可搜索到对应的命令实现类,这里Command类会被包装 AnnotatedCommand 类放入列表中。
五、Arthas 快速入门讲解
5.1 启动 Arthas
# 第一重方式
./as.sh# 第二种方式(推荐)
java -jar arthas-boot.jar
5.2 基础命令介绍
# 启动服务
java -jar arthas-boot.jar
# 查看帮助
help
- base64 :base64 编码转换,和 linux 里的 base64 命令类似
- cat :打印文件内容,和 linux 里的 cat 命令类似
- cls:清空当前屏幕区域
- echo:打印参数,和 linux 里的 echo 命令类似
- grep:匹配查找,和 linux 里的 grep 命令类似
- help:查看命令帮助信息
- history:打印命令历史
- keymap:Arthas 快捷键列表及自定义快捷键
- pwd:返回当前的工作目录,和 linux 命令类似
- quit:退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
- reset:重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
- session:查看当前会话的信息
- stop:关闭 Arthas 服务端,所有 Arthas 客户端全部退出
- tee: 复制标准输入到标准输出和指定的文件,和 linux 里的 tee 命令类似
- version:输出当前目标 Java 进程所加载的 Arthas 版本号
5.3 jvm 相关命令行
# 启动服务
java -jar arthas-boot.jar
# 查看帮助
help
- dashboard:当前系统的实时数据面板
- getstatic:查看类的静态属性
- heapdump:dump java heap, 类似 jmap 命令的 heap dump 功能
- jvm:查看当前 JVM 的信息
- logger:查看和修改 logger
- mbean:查看 Mbean 的信息
- memory:查看 JVM 的内存信息
- ognl:执行 ognl 表达式
- perfcounter:查看当前 JVM 的 Perf Counter 信息
- sysenv:查看 JVM 的环境变量
- sysprop:查看和修改 JVM 的系统属性
- thread:查看当前 JVM 的线程堆栈信息
- vmoption:查看和修改 JVM 里诊断相关的 option
- vmtool:从 jvm 里查询对象,执行 forceGc
1、dashboard(实时数据面板)
dashboard
数据说明:
- ID:Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应
- NAME:线程名
- GROUP:线程组名
- PRIORITY:线程优先级, 1~10之间的数字,越大表示优先级越高
- STATE:线程的状态
- CPU%:线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。
- TIME:线程运行总时间,数据格式为分:秒
- INTERRUPTED:线程当前的中断位状态
- DAEMON:是否是daemon线程
GC区域说明:
- gc.ps_scavenge.count:从应用程序启动到当前采样时间年轻代gc次数
- gc.ps_scavenge.time(ms):从应用程序启动到当前采样时间年轻代gc所用的总时间(毫秒)
- gc.ps_marksweep.count:从应用程序启动到当前采样时间老年代gc次数
- gc.ps_marksweep.time(ms):从应用程序启动到当前采样时间老年代gc所用的总时间(毫秒)
Memory 区域主要参数说明:
- heap:堆内存使用情况(ps_eden_space+ps_survivor_space+ps_old_gen)
- ps_eden_space:伊甸园区内存使用情况
- ps_survivor_space:幸存区内存使用情况
- ps_old_gen :老年代内存使用情况
- nonheap:非堆内存使用情况
输入 q 或者 Ctrl+C 可以退出dashboard命令
2、Thread(线程相关堆栈信息)
参数说明:
- 数字:线程id
- [n:]:指定最忙的前N个线程并打印堆栈
- [b]:找出当前阻塞其他线程的线程
- [i ] :指定cpu占比统计的采样间隔,单位为毫秒
Arthas支持管道,可以用 thread 1 | grep 'main(' 查找到main class。
thread 1 | grep 'main('thread # 显示所有线程的信息
thread 1 # 显示1号线程的运行堆栈
thread -b # 查看阻塞的线程信息
thread -n 3 # 查看最忙的3个线程,并打印堆栈
thread -i 1000 -n 3 # 指定采样时间间隔,每过1000毫秒采样,显示最占时间的3个线程# 查看处于等待状态的线程(WAITING、BLOCKED)
thread --state WAITING
死锁线程查看
thread # 查看线程状态
thread -b # 查看阻塞的线程信息
3、jvm(查看当前 JVM 的信息)
jvm
THREAD相关
- COUNT:JVM当前活跃的线程数
- DAEMON-COUNT: JVM当前活跃的守护线程数
- PEAK-COUNT:从JVM启动开始曾经活着的最大线程数
- STARTED-COUNT:从JVM启动开始总共启动过的线程次数
- DEADLOCK-COUNT:JVM当前死锁的线程数
文件描述符相关
- MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数
- OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数
4、memory(查看 JVM 的内存信息)
memory
5、sysprop(查看/修改属性)
sysprop # 查看所有属性
sysprop java.version # 查看单个属性,支持通过tab补全
修改某个属性
sysprop user.country
user.country=US
6、sysenv(查看当前JVM的环境属性)
# 查看所有环境变量
sysenv
# 查看单个环境变量
sysenv USER
7、vmoption(查看JVM中选项)
# 查看所有的选项
vmoption
# 查看指定的选项
vmoption PrintGCDetails
# 更新指定的选项
vmoption PrintGCDetails true
8、getstatic(获取静态成员变量)
# 语法
getstatic 类名 属性名
# 显示demo.MathGame类中静态属性random
getstatic demo.MathGame random
9、ognl(执行ognl表达式)
执行ognl表达式,这是从3.0.5版本新增的功能。
参数说明:
- express:执行的表达式
- [c:]:执行表达式的 ClassLoader 的 hashcode,默认值是SystemClassLoader
- [x]:结果对象的展开层次,默认值1
举例:
调用静态函数
# 获取系统变量中值,并且打印(只会打印有返回值函数)
ognl '@java.lang.System@out.println("hello")'
获取静态类的静态字段
# 获取代码中的运行返回值
ognl '@demo.MathGame@random'
执行多行表达式,赋值给临时变量,返回一个List
# 计算value1、value2值,并存在List集合中
ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
5.4 类和类加载器(class/classLoader)
- classloader:查看 classloader 的继承树,urls,类加载信息,使用 - classloader:去 getResource
- dump:dump 已加载类的 byte code 到特定目录
- jad:反编译指定已加载类的源码
- mc:内存编译器,内存编译.java文件为.class文件
- redefine:加载外部的.class文件,redefine 到 JVM 里
- retransform:加载外部的.class文件,retransform 到 JVM 里
- sc:查看 JVM 已加载的类信息
- sm:查看已加载类的方法信息
1、sc(查看类信息)
查看类的信息(sc: Search Class)
- 查看JVM已加载的类信息,“Search-Class” 的简写,这个命令能搜索出所有已经加载到 JVM 中的 Class 信息
- sc 默认开启了子类匹配功能,也就是说所有当前类的子类也会被搜索出来,想要精确的匹配,请打开options disable-sub-class true开关。
参数说明:
- class-pattern:类名表达式匹配,支持全限定名,如com.taobao.test.AAA,也支持com/taobao/test/AAA这样的格式,这样,我们从异常堆栈里面把类名拷贝过来的时候,不需要在手动把/替换为.啦。
- method-pattern:方法名表达式匹配
- [d]:输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。 如果一个类被多个ClassLoader所加载,则会出现多次
- [E]:开启正则表达式匹配,默认为通配符匹配
- [f]:输出当前类的成员变量信息(需要配合参数-d一起使用)
# 模糊搜索,demo包下所有的类
sc demo.*
# 打印类的详细信息
sc -d demo.MathGame
2、sm(查看已加载方法信息)
查看已加载方法信息(“Search-Method” )
- 查看已加载类的方法信息“Search-Method” 的简写,这个命令能搜索出所有已经加载了 Class 信息的方法信息。
- sm 命令只能看到由当前类所声明 (declaring) 的方法,父类则无法看到。
参数说明:
- class-pattern:类名表达式匹配
- method-pattern:方法名表达式匹配
- [d]:展示每个方法的详细信息
- [E]:开启正则表达式匹配,默认为通配符匹配
# 显示String类加载的方法
sm java.lang.String
# 查看方法信息
sm demo.MathGame
# 查看方法信息(详细信息-d)
sm -d demo.MathGame
3、编译与反编译jad、mc、redefine
- jad:反编译字节码文件得到java的源代码
- mc:在内存中将源代码编译成字节码
- redefine:将字节码文件重新加载到内存中执行
【示例】jad 反编译已加载类源码
# 反编译MathGame方法
jad demo.MathGame
# 反编绎时只显示源代码(排除ClassLoader信息)。
# 默认情况下,反编译结果里会带有ClassLoader信息,通过--source-only选项,可以只打印源代码。方便和mc/redefine命令结合使用。
jad --source-only demo.MathGame
# 反编译到指定文件中
jad --source-only demo.MathGame > Hello.java
# 只反编译mathGame类型中main方法
jad demo.MathGame main
【示例】mc 编译Java代码
# 在内存中编译Hello.java为Hello.class
mc /root/Hello.java
# 可以通过-d命令指定输出目录
mc -d /root/bbb /root/Hello.java
【示例】redefine 加载外部.class文件
redefine的限制
- 不允许新增加field/method
- 正在跑的函数,没有退出不能生效,比如下面新增加的System.out.println,只有run()函数里的会生效。
# 1. 使用jad反编译demo.MathGame输出到/root/MathGame.java
jad --source-only demo.MathGame > /root/MathGame.java
# 2.按上面的代码编辑完毕以后,使用mc内存中对新的代码编译
mc /root/MathGame.java -d /root
# 3.使用redefine命令加载新的字节码
redefine /root/demo/MathGame.class
4、dump(保存已加载字节码文件到本地)
将已加载类的字节码文件保存在特定目录:logs/arthas/classdump
- 不同的类加载器放在不同的目录下。
- dump作用:将正在JVM中运行的程序的字节码文件提取出来,保存在logs相应的目录下。
参数说明:
- class-pattern:类名表达式匹配
- [c:]:类所属 ClassLoader 的 hashcode
- [E]:开启正则表达式匹配,默认为通配符匹配
# 把String类的字节码文件保存到~/logs/arthas/classdump/目录下
dump java.lang.String
# 把demo包下所有的类的字节码文件保存到~/logs/arthas/classdump/目录下
dump demo.*
5、classloader(获取类加载器的信息)
作用:
- classloader 命令将 JVM 中所有的 classloader 的信息统计出来,并可以展示继承树,urls等。
- 可以让指定的 classloader 去 getResources,打印出所有查找到的resources的 url。对于ResourceNotFoundException异常比较有用。
参数说明:
- [l]:按类加载实例进行统计
- [t]:打印所有ClassLoader的继承树
- [a]:列出所有ClassLoader加载的类,请谨慎使用
- [c:]:ClassLoader的hashcode
- [c: r:]:用ClassLoader去查找resource
- [c: load:]:用ClassLoader去加载指定的类
# 默认按类加载器的类型查看统计信息
classloader
# 按类加载器的实例查看统计信息,可以看到类加载的hashCode
classloader -l
# 查看ClassLoader的继承树
classloader -t
# 通过类加载器的hash,查看此类加载器实际所在的位置
classloader -c 680f2737
# 使用ClassLoader去查找指定资源resource所在的位置
classloader -c 680f2737 -r META-INF/MANIFEST.MF
# 使用ClassLoader去加载类
classloader -c 70dea4e --load java.lang.String
classloader命令主要作用有哪些?
- 显示所有类加载器的信息
- 获取某个类加载器所在的jar包
- 获取某个资源在哪个jar包中
- 加载某个类
5.5 monitor/watch/trace 相关(核心监视功能)
- monitor - 方法执行监控
- stack - 输出当前方法被调用的调用路径
- trace - 方法内部调用路径,并输出方法路径上的每个节点上耗时
- tt - 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
- watch - 方法执行数据观测
1、monitor(监控方法的执行情况)
监控指定类中方法的执行情况用来监视一个时间段中指定方法的执行次数,成功次数,失败次数,耗时等这些信息。
参数说明:
- class-pattern:类名表达式匹配
- method-pattern:方法名表达式匹配
- [E]:开启正则表达式匹配,默认为通配符匹配
- [c:]:统计周期,默认值为120秒
监控demo.MathGame类,并且每5S更新一次状态。
monitor demo.MathGame primeFactors -c 5
监控的维度说明:
- timestamp:时间戳
- class:Java类
- method:方法(构造方法、普通方法)
- total:调用次数
- success:成功次数
- fail:失败次数
- rt:平均耗时
- fail-rate:失败率
2、watch(检测函数返回值)
方法执行数据观测,让你能方便的观察到指定方法的调用情况。能观察到的范围为:返回值、抛出异常、入参,通过编写OGNL 表达式进行对应变量的查看。
参数说明:
- class-pattern:类名表达式匹配
- method-pattern 方法名表达式匹配
- express 观察表达式
- condition-express 条件表达式
- [b]:在方法调用之前观察before
- [e]:在方法异常之后观察 exception
- [s]:在方法返回之后观察 success
- [f]:在方法结束之后(正常返回和异常返回)观察 finish
- [E]:开启正则表达式匹配,默认为通配符匹配
- [x:]:指定输出结果的属性遍历深度,默认为 1
这里重点要说明的是观察表达式,观察表达式的构成主要由ognl 表达式组成,所以你可以这样写"{params,returnObj}",只要是一个合法的 ognl 表达式,都能被正常支持。
特别说明:
- watch 命令定义了4个观察事件点,即 -b 方法调用前,-e 方法异常后,-s 方法返回后,-f 方法结束后
- 4个观察事件点-b、-e、-s 默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出
- 这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,除了 -b 事件点 params 代表方法入参外,其余事件都代表方法出参
- 当使用 -b 时,由于观察事件点是在方法调用前,此时返回值或异常均不存在
# 查看方法执行的返回值
watch demo.MathGame primeFactors returnObj
# 观察demo.MathGame类中primeFactors方法出参和返回值,结果属性遍历深度为2。
# params:表示所有参数数组(因为不确定是几个参数)。
# returnObject:表示返回值
watch demo.MathGame primeFactors "{params,returnObj}" -x 2# 查看执行前参数:
# -b 方法执行前的参数
watch demo.MathGame primeFactors "{params,returnObj}" -x 2 -b# 查看方法中的属性
watch demo.MathGame primeFactors "{target}" -x 2 -b# 查看某一属性的值
watch demo.MathGame primeFactors "{target.illegalArgumentCount}" -x 2 -b# 检测方法在执行前-b、执行后-s的入参params、属性target和返回值returnObj
watch demo.MathGame primeFactors "{params,target,returnObj}" -x 2 -b -s -n 2# 输入参数小于0的情况:
watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0"
3、trace(根据路径追踪,并记录消耗时间)
对方法内部调用路径进行追踪,并输出方法路径上的每个节点上耗时。
- trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。
- 观察表达式的构成主要由ognl 表达式组成,所以你可以这样写"{params,returnObj}",只要是一个合法的 ognl 表达式,都能被正常支持。
- 很多时候我们只想看到某个方法的rt大于某个时间之后的trace结果,现在Arthas可以按照方法执行的耗时来进行过滤了,例如trace *StringUtils isBlank '#cost>100'表示当执行时间超过100ms的时候,才会输出trace的结果。
- watch/stack/trace 这个三个命令都支持#cost耗时条件过滤。
参数说明:
- class-pattern:类名表达匹配
- method-pattern:方法名表达式匹配
- condition-express:条件表达式,使用OGNL表达式
- [E]:开启正则表达式匹配,默认是通配符匹配
- [n:]:设置命令执行次数
- #cost:方法执行耗时,单位是毫秒
# trace函数指定类的指定方法
trace demo.MathGame run# 执行1次后退出
trace demo.MathGame run -n 1# 默认情况下,trace不会包含jdk里的函数调用,如果希望trace jdk里的函数。
# 需要显式设置--skipJDKMethod false。
trace --skipJDKMethod false demo.MathGame run# 据调用耗时过滤,trace大于0.5ms的调用路径
trace demo.MathGame run '#cost > .5'# 可以用正则表匹配路径上的多个类和函数,一定程度上达到多层trace的效果。
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3
4、stack(输出当前方法被调用的调用路径)
输出当前方法被调用的调用路径很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从那里被执行了,此时你需要的是 stack 命令。
参数说明:
- class-pattern:类名表达式匹配
method-pattern:方法名表达式匹配
condition-express:条件表达式,OGNL
[E]:开启正则表达式匹配,默认为通配符匹配
[n:]:执行次数限制
# 获取primeFactors的调用路径
stack demo.MathGame primeFactors# 条件表达式来过滤,第0个参数的值小于0,-n表示获取2次
stack demo.MathGame primeFactors 'params[0]<0' -n 2# 据执行时间来过滤,耗时大于0.5毫秒
stack demo.MathGame primeFactors '#cost>0.5'
5、tt(时间隧道,记录多个请求)
time-tunnel 时间隧道。记录下指定方法每次调用的入参和返回信息,并能对这些不同时间下调用的信息进行观测。
- watch 虽然很方便和灵活,但需要提前想清楚观察表达式的拼写,这对排查问题而言要求太高,因为很多时候我们并不清楚问题出自于何方,只能靠蛛丝马迹进行猜测。
- 这个时候如果能记录下当时方法调用的所有入参和返回值、抛出的异常会对整个问题的思考与判断非常有帮助。于是乎,TimeTunnel 命令就诞生了。
- 作用:记录指定方法每次调用的入参和返回值,并后期还可以对这些信息进行观测。
参数说明:
- -t:记录某个方法在一个时间段中的调用
- -l:显示所有已经记录的列表
- -n:次数 只记录多少次
- -s:表达式 搜索表达式
- -i:索引号 查看指定索引号的详细调用信息
- -p:重新调用:指定的索引号时间碎片
# 最基本的使用来说,就是记录下当前方法的每次调用环境现场。
tt -t demo.MathGame primeFactors
字段说明:
- INDEX 时间片段记录编号,每一个编号代表着一次调用,后续tt还有很多命令都是基于此编号指定记录操作,非常重要。
- TIMESTAMP 方法执行的本机时间,记录了这个时间片段所发生的本机时间
- COST(ms) 方法执行的耗时
- IS-RET 方法是否以正常返回的形式结束
- IS-EXP 方法是否以抛异常的形式结束
- OBJECT 执行对象的hashCode(),注意,曾经有人误认为是对象在 JVM中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体
- CLASS 执行的类名
- METHOD 执行的方法名
# 对现有记录进行检索
tt -l
# 需要筛选出 `primeFactors` 方法的调用信息
tt -s 'method.name=="primeFactors"'
# 查看某条记录详细信息
tt -i 1002
5.6 profiler 火焰图
profiler 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。
常用命令:
profiler | 命令作用 |
profiler start | 启动profiler,默认情况下,生成cpu的火焰图 |
profiler list | 显示所有支持的事件 |
profiler getSamples | 获取已采集的sample的数量 |
profiler status | 查看profiler的状态,运行的时间 |
profiler stop | 停止profiler,生成火焰图的结果,指定输出目录和输出格式:svg或html |
启动profiler
profiler start
默认情况下,生成的是cpu的火焰图,即event为cpu。可以用--event参数来指定。
显示支持的事件
profiler list
获取已采集的sample的数量
profiler getSamples
查看profiler状态(可以查看当前profiler在采样哪种event和采样时间。)
profiler status
停止profiler,并同步生成文件(默认在工作目录下的arthas-output目录。)
[arthas@99095]$ profiler stop
OK
profiler output file: /opt/arthas/arthas-output/20231203-171828.html
通过 --file 参数来指定输出结果路径
# 指定生成的文件名以及路径
profiler stop --file /tmp/result.svg
可以用--format 指定生成格式
profiler stop --format html
生成的图(把输出的文件用浏览器打开):
火焰图的含义:火焰图是基于 perf 结果产生的SVG 图片,用来展示 CPU 的调用栈。
- y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数。
- x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。
- 火焰图就是看顶层的哪个函数占据的宽度最大。只要有"平顶"(plateaus),就表示该函数可能存在性能问题。
- 颜色没有特殊含义,因为火焰图表示的是 CPU 的繁忙程度,所以一般选择暖色调。
相关文章:

JVM内存分析工具-Arthas 教程[详细]
一、概述 Arthas(阿尔萨斯)是阿里巴巴开源的一款Java诊断工具,用于实时检测、诊断Java应用程序的性能问题。它是一个命令行工具,提供了丰富的功能,包括查看类加载信息、方法执行耗时、线程堆栈、内存分析等。Arthas 的…...

Google发布开放的模型Gemma
今天,Google 发布了一系列最新的开放式大型语言模型 —— Gemma!Google 正在加强其对开源人工智能的支持,我们也非常有幸能够帮助全力支持这次发布,并与 Hugging Face 生态完美集成。 Gemma 提供两种规模的模型: 7B …...

谷歌掀桌子!开源Gemma:可商用,性能超过Llama 2!
2月22日,谷歌在官网宣布,开源大语言模型Gemma。 Gemma与谷歌最新发布的Gemini 使用了同一架构,有20亿、70亿两种参数,每种参数都有预训练和指令调优两个版本。 根据谷歌公布的测试显示,在MMLU、BBH、GSM8K等主流测试…...

http缓存?强制缓存和协商缓存?
HTTP缓存是一种优化网络资源加载速度的技术,通过减少从服务器获取相同资源的次数来实现。HTTP缓存机制包括强制缓存和协商缓存(对比缓存)两种类型。 强制缓存 强制缓存是指浏览器在接收到服务器返回的响应后,会将响应内容和相关…...

技术心得--如何成为优秀的架构师
关注我,持续分享逻辑思维&管理思维; 可提供大厂面试辅导、及定制化求职/在职/管理/技术辅导; 有意找工作的同学,请参考博主的原创:《面试官心得--面试前应该如何准备》,《面试官心得--面试时如何进行自…...

【Unity】【VR开发】Unity云同步功能使用心得
【背景】 有时出差,旅行等等也带着电脑,晚上想要继续编辑项目,就需要用到云同步功能。目前实践下来,发现有些内容可以同步,有些内容则是不可以同步的,总结如下。 【如何云同步一个本地项目】 UnityHub的项目面板中有两个选项卡:项目和云端项目。 鼠标挪动到想要云同步…...

vscode侧边框关掉了怎么打开
View - Appearance - Secondary Side Bar 就可以显示出来了,例如 :(CodeGeeX不显示主界面)...

YOLO-NAS浅析
YOLO-NAS(You Only Look Once - Neural Architecture Search)是一种基于YOLO(You Only Look Once)的目标检测算法,结合神经架构搜索(NAS)技术来优化模型性能。 YOLO是一种实时目标检测算法&…...

LeetCode 2656.K个元素的最大和
给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。你需要执行以下操作 恰好 k 次,最大化你的得分: 从 nums 中选择一个元素 m 。 将选中的元素 m 从数组中删除。 将新元素 m 1 添加到数组中。 你的得分增加 m 。 请你返回执行以上操作恰好 k 次后…...

【最新Dubbo3深入理解】Dubbo3核心Tripple协议详解
欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送! 在我后台回复 「资料」 可领取编程高频电子书! 在我后台回复「面试」可领取硬核面试笔记! 文章导读地址…...

神秘人暗访:行政窗口为什么要开展神秘顾客调研
在竞争日益激烈的服务市场中,行政窗口作为公共服务的直接提供者,其服务质量的好坏直接关系到政府的形象和公众对政府的信任度。为了更好地满足市民的需求,提升服务质量,开展神秘顾客调查显得尤为重要。神秘顾客调查的必要性包括以…...

Spring之AOP
文章目录 初步实现通知执行顺序 各个通知获取细节信息重用切点表达式切点表达式语法细节环绕增强切面的优先级没有接口的情况基于XML的AOP[了解] 初步实现 先导入Spring和Junit4的依赖 <dependency><groupId>org.springframework</groupId><artifactId&g…...

Git详解及 github与gitlab使用
目录 1.1 关于版本控制 1.1.1 本地版本控制 1.1.2 集中化的版本控制系统 1.1.3 分布式版本控制系统 1.2 Git简介 1.2.1 Git历史 1.3 安装git 1.3.1 环境说明 1.3.2 Yum安装Git 1.3.3 编译安装 1.4 初次运行 Git 前的配置 1.4.1 配置git 1.4.2 获取帮助 1.5 获取 G…...
政安晨:【完全零基础】认知人工智能(二)【超级简单】的【机器学习神经网络】—— 底层算法
如果小伙伴第一次看到这篇文章,可以先浏览一下我这个系列的上一篇文章: 政安晨:【完全零基础】认知人工智能(一)【超级简单】的【机器学习神经网络】 —— 预测机https://blog.csdn.net/snowdenkeke/article/details/…...

基于springboot+vue的美发门店管理系统(前后端分离)
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 主要内容:毕业设计(Javaweb项目|小程序|Pyt…...

C语言第二十八弹---整数在内存中的存储
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 目录 1、整数在内存中的存储 2、大小端字节序和字节序 2.1、什么是大小端? 2.2、为什么有大小端? 2.3、练习 2.3.1、练习1 2.3.2、练习2 2.…...

java开源xml工具类介绍
在Java中处理XML的常用开源工具有很多,以下是一些流行的库以及简单的示例代码: DOM4J DOM4J 是一个非常流行的Java库,用于处理XML,DOM4J 易于使用,并且提供了很好的性能。 Maven 依赖 …...

Go 语言一些常用语法编写和优化指南
Go 语言以其简洁的语法和强大的并发性能而受到开发者的喜爱。然而,为了充分利用 Go 的潜力,我们需要了解如何优化 Go 程序。本文将介绍一些常见的 Go 语言优化技巧,并通过实际例子进行说明。 推荐系列 来来来,老铁们,男人女人都需要的技术活…...

Golang 语法系列:结构体
结构体:相当于"类" 1.结构体声明 type [name] struct {[field_name] [field_type][field_name] [field_type]... }//例子:type Person struct {name stringage int }其中field_name可以省略 2.结构体的使用 1) 格式1 var person Person p…...

关于iPad中的密码和触控ID的使用,看这篇文章就差不多了
序言 许多苹果iPad型号都有熟悉的密码系统和触控ID,这需要指纹扫描才能解锁设备。本指南向你展示如何使用iPad Air 2或更高版本、iPad Mini 3或更新版本以及iPad Pro设置或更改密码和触控ID指纹。 一些iPad Pro型号支持面部识别,并配备了面容ID而不是触控ID作为安全功能。面…...

Vue3之ref与reactive的基本使用
ref可以创建基本类型、对象类型的响应式数据 reactive只可以创建对象类型的响应式数据 接下来让我为大家介绍一下吧! 在Vue3中,我们想让数据变成响应式数据,我们需要借助到ref与reactive 先为大家介绍一下ref如何使用还有什么注意点 我们需…...

wsl内置Ubuntu使用 Dinky 与 Flink 集成
Dinky 与 Flink 集成 说明 本文档介绍 Dinky 与 Flink 集成的使用方法, 如果您是 Dinky 的新用户, 请先阅读 本文档, 以便更好的搭建 Dinky 环境 如果您已经熟悉 Dinky 并已经部署了 Dinky, 请跳过本文档的前置要求部分, 直接阅读 Dinky 与 Flink 集成部分 注意: 本文档基…...

”戏说“ 交换机 与 路由器
一般意义上说 老哥 这文章发表 的 东一榔头 西一锤 呵呵, 想到哪里就啰嗦到哪里 。 交换机: 其实就是在通道交换 路由器: 不光是在通道交换还要在协议上交换 下图你看懂了吗? (仅仅数据交换-交换机 协议…...

Linux pageset
1. 引言 在用户进程发生缺页异常时,Linux内核需要分配所需物理页面以及建立也表映射,来维持进程的正常内存使用需求。而对于分配物理页面仅依赖于buddy系统,对于小order页面的分配效率较低。因此Linux通过在每个cpu维护一个page链表ÿ…...

【C++之语法篇003】
C学习笔记---003 C知识开篇1、内联函数1.1、什么是内联函数?1.2、解决外部头文件,重复定义问题1.3、内联函数的总结 2、auto关键字2.1、auto的作用2.2、auto的总结 3、范围for3.1、什么是范围for?3.2、范围for的循环应用 4、指针空值关键字nullptr4.1、…...

Github代码仓库SSH配置流程
作者: Herman Ye Auromix 测试环境: Ubuntu20.04 更新日期: 2024/02/21 注1: Auromix 是一个机器人爱好者开源组织。 注2: 由于笔者水平有限,以下内容可能存在事实性错误。 相关背景 在为Github代码仓库配…...

Arrays工具类的常见方法总结
一、Arrays.asList( ) 1.作用:Arrays.asList( )方法的作用是将数组转换成List,将List中的全部集合对象添加至ArrayList集合中 2.参数:动态参数 (T... a) 3.返回值:List 集合 List<T> 4.举例: package com…...

物联网和人工智能的融合
物联网和人工智能的融合 1. 物联网和人工智能的融合2. 芯片技术的进步3. 安全和隐私保护挑战4. 软件开发和调试技术的创新5. 自动化和智能化趋势 1. 物联网和人工智能的融合 随着物联网和人工智能技术的快速发展,嵌入式系统将更多地与物联网设备和人工智能算法相结…...

【微信小程序】wxss 和 css 、wxml 和 html 区别
wxss 和 css 区别 wxss 支持小程序特有的选择器和 样式属性 scroll-into-view cover-view 等wxss 引入了 rpx 单位,可以根据屏幕宽度进行自适应,使得开发者可以更方便的处理不同尺寸屏幕的适配问题。wxss 背景图片只能引入外链,不能使用本地…...

python统计分析——使用AIC进行模型选择
参考资料:用python动手学统计学 1、导入库 # 导入库 # 用于数值计算的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 用于绘图的库 import matplotlib.pyplot as plt import seaborn as sns sns.set() # 用于估计统计…...