前言
问题:这个月你的代码把服务器干崩了几次?
现今服务器内存降低,需要业务开发做JVM调优的越来越少,但是!总是偶有几个“优秀”的同事,一不小心写出个让服务器CPU飙高、内存炸裂的代码,服务瞬间从“赛亚人”变成“战五渣”。
虽说不再需要大家对JVM调优,但是会看JVM堆栈信息,排查定位问题,是逃不了的。今天来分享一个我用多年的“抓鬼”工具——VisualVM,它就像JVM界的“监控探头”,把服务器上发生的猫腻,尽收眼底。
为什么是VisualVM
- 免费 —— 首先就是因为它白嫖啊!这年头,能白嫖的绝不花钱,懂的都懂
- 有界面 —— 告别黑乎乎的命令行
- 本地开发调试压测 —— 个人做实验和生产问题复现,这个用得比较多,靠它实时盯着JVM的一举一动
- 实时监控CPU、内存、线程、GC —— 还能远程连接,虽然我们公司运维环境不给开(别问,问就是为了安全)
- 支持分析离线Dump文件 —— 服务器挂都挂了,它就是“尸体”解剖手术台
下面我就重点讲两种我最常用的场景:本地开发调试压测、离线解剖Dump文件。先给大家看下正文目录大纲:
1 本地开发环境调试GC监控
1.1 先把项目跑起来
我用的是Idea,你们用啥都行,反正Java项目跑起来就完事了
1.2 派出狗仔队监控
启动VisualVM实时监控项目,VisualVM启动在Java项目启动之前和之后都行,因为它是会自动定时扫描当前系统中所有正在运行的 Java 进程,并将相关的环境信息自动统计成图形界面
1.2.1 Overview-环境静态信息
主要是些Java版本、JVM参数、系统属性,这些静态的参数信息,大多数时候不需要关注,了解一下就行。
1.2.2 Monitor-JVM实时监控信息
这个页签重要指数5颗星,CPU曲线、堆内存使用、类加载数量、线程活动,全给你实时画成图。当你压测的时候,看着CPU曲线像过山车一样飙升,看到堆内存那条线跟吃了炫迈一样,一直往上走,根本停不下来——这时候你就知道,该去代码里抓鬼了。
使用案例: 线程池用完不Shutdown,CPU和内存都快哭了
1.2.3 Threads-线程实时监控信息
多线程这东西,用好了是并行处理,用不好就是死锁、活锁、无限等待。这个页签你可以看看线程们哪些在996干工作,哪些在扯皮误事
1.2.4 Sampler-CPU和内存采样器
这个tab页面主要收集特定时间间隔内的性能采样数据:
- CPU采样分析:定位到具体的方法,清晰地显示哪些方法消耗了最多的CPU时间
- 内存采样分析:显示哪些类创建了最多的对象,以及这些对象占用了多少内存快速发现内存泄漏,非常有帮助,能快速定位到可疑的类
1.2.5 Profiler-性能分析器
Profiler页面能提供运行期间方法级的CPU执行次数和执行时间统计分析以及内存分析(比Sampler页面更精确),如:
- CPU分析会统计方法执行次数、执行耗时;
- 内存分析会统计每个方法关联的对象数以及这些对象占用的空间
需要注意,这个页面的信息统计对被监控应用的性能产生一定影响,一般不在生产环境中开启。
1.3 扩展知识
1.4 补充说明
VisualVM 不仅支持监控本地 JVM,还可以通过 JMX 连接远程 JVM,因为我所处的公司环境不支持,本文不做远程连接的讲解
本地项目的监控JMX代理服务自动暴露,VisualVM 自动发现,无需配置。
但是如果需要连接远程监控,需要在远程服务器的 Java 进程启动参数中显式添加 -Dcom.sun.management.jmxremote 等参数,以开启远程 JMX 服务,并配置端口、主机名等,才能让 VisualVM 从远程连接。
2 离线解剖Dump文件
2.1 获取Dump文件
服务器崩了之后,赶紧找运维要Dump文件。一般是个xxx.hprof.tar.gz,解压后得到xxx.hprof。
这个文件可不小,动不动就几个G,加载的时候可以先去泡杯咖啡。
2.2 使用VisualVM打开
2.3 解读文件数据指标
加载hprof文件后你会看到一堆数据指标,别慌,我给你一个一个拆解,下面分块进行说明
使用案例可以看:Redisson分布式锁引发的线上内存泄露问题
2.3.1 模块1-概览信息
- Heap Size: 总堆大小为1,056,253,592字节(约1GB)。
- Classes: 加载了35,732个类。
- Instances: 总共有22,560,323个实例对象。
- ClassLoaders: 有1,155个类加载器。
- GC Roots: 有31,352个GC根。
- Objects Pending for Finalization: 没有对象等待最终化。
2.3.2 模块2-环境信息
- System: 运行在Linux系统上,版本为5.14.0-284.25.1.el9_2.x86_64。
- Architecture: amd64 64位架构。
- Java Home: Java安装目录为/opt/java/openjdk。
- Java Version: 使用的Java版本为11.0.18,OpenJDK 64-Bit Server VM。
- Java Vendor: Java供应商为Eclipse Adoptium。
- JVM Uptime: JVM已经运行了39分钟6秒。
2.3.3 模块3-环境参数
这里可以点击查看到环境设置的相关参数信息
- JVM Arguments: JVM相关参数。
- Enable Modules:JDK依赖的可使用的插件。
- System Properties: 系统环境相关的参数。
2.3.4 模块4-类实例数量(重要)
按实例数量排序的类,它列出了内存中每种类的实例数量,并按数量从多到少排序。
可以用来识别哪些类创建了大量实例。如果某个类的实例数量异常高,可能表明存在内存泄漏或不必要的对象创建。
例如: java.util.concurrent.ConcurrentHashMap$Node类实例占22.6%,java.util.concurrent.ConcurrentHashMap$Node类的实例数量非常高,可能意味着程序中大量使用了ConcurrentHashMap,或者ConcurrentHashMap的某些操作导致对象没有被及时回收。
2.3.5 模块5-类实例占内存大小(重要)
按类实例占用总内存大小排序的类。它列出了每种类的所有实例占用的总内存大小,并按大小从大到小排序。
可以用来识别哪些类的实例占用了大量内存。如果某个类的实例占用的内存非常大,可能表明这些对象包含大量数据或引用了大量其他对象。
例如: 图例中byte[]类占用内存最多,占23.5%,其次是java.util.concurrent.ConcurrentHashMap$Node类,占20.3%。
2.3.6 模块6-单个实例大小(重要)
按单个实例大小排序的实例。它列出了内存中每个具体实例占用的内存大小,并按大小从大到小排序。
可以用来识别单个实例中占用内存最大的对象。这些对象可能是内存泄漏的源头,或者是需要优化的对象。
例如: java.util.concurrent.ConcurrentHashMap$Node实例占用内存最多,占1.6%。意味着这个对象中有大量对其他对象的引用,需要进一步分析其内容和引用关系。
2.3.7 模块7-支配对象的深堆大小(重要)
按保留大小排序的对象支配者。它列出了内存中每个支配者对象及其支配的对象所占用的内存大小,并按大小从大到小排序。
可以用来识别哪些对象是内存使用的主要支配者。如果某个对象的保留大小非常大,可能意味着它及其引用的对象占用了大量内存。
例如: 如果org.redisson.pubsub.PublishSubscribeService对象的保留大小最大,可能意味着这个对象及其引用的对象占用了大量内存,需要进一步分析其引用关系和内存使用情况。
2.4 扩展知识
浅堆、深堆、实际大小,傻傻分不清?
-
ShallowHeap(浅堆) 一个对象的浅堆是指一个对象本身的大小,即当前对象的对象头(8字节)+该对象中若干个对象的引用(4字节),不包括这个对象内部引用的其他对象的实际大小。可以结合对象发生浅拷贝时,仅仅只会拷贝当前对象的本身的内容理解
-
RetainedHeap(深堆) RetainedSet(保留集)是指的一个对象被回收后能释放的所有对象的集合,例如:对象A的保留集指的是只能通过对象A直接或者间接被引用。所以Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用) 。 深堆大小是指对象的保留集中所有对象的浅堆大小。
-
对象的实际大小 对象的实际大小是指的这个对象直接或者间接能到达的所有对象的大小。这里注意与深堆概念的区分。
-
区别说明
上面是一个简单的对象引用关系图,对象A直接引用了C、E,间接引用D,对象B直接引用E。
- A的浅堆大小只是A本身,不含C和D、E;
- A的深堆大小为A、C、D之和,由于对象E还可以通过对象B访问到,因此不在对象A的深堆范围内。
- A的实际大小为A、C、D、E 4个对象之和。
一句话总结:
- 浅堆 = 你自己有多重
- 深堆 = 你和你养的宠物、宠物养的跳蚤的总重量(但跳蚤如果还能被隔壁老王养着,就不算)
- 实际大小 = 你能接触到的所有东西的总重量
最后
VisualVM是我用得比较顺手的工具,但其实它还有很多高级功能和细节的地方我没有展开,比如OQL对象查询语言(类似SQL查对象)、插件扩展等等。
如果你有更好用的工具,或者对VisualVM有更深的理解,欢迎在评论区分享。毕竟技术这东西,大家一起卷才有意思。
wx 公众号、知乎 同名,欢迎来讨论!!!
wx 公众号、知乎 同名,欢迎来讨论!!!
wx 公众号、知乎 同名,欢迎来讨论!!!