这个问题面试时问过很多次,之前只看过一些八股,但没有操作过,所以回答的时候都很模糊不自信,今天模拟下加深印象。
!!!参考链接请点这里!!!
模拟一次 OOM 异常的定位流程
#JVM调优相关工具
JDK 工具
JDK 自身带了很多工具,来监控系统和排查内存性能问题,这些工具都存放在 bin 目录中
工具 | 类型 | 作用 |
---|---|---|
jps | 命令行 | JVM 进程状态工具,列出系统上的 JVM 进程 |
jinfo | 命令行 | JVM 信息查看工具,查看 JVM 的各种配置信息 |
jvisualvm | 图形界面 | 综合的 JVM 监控工具,查看 JVM 的基本情况、做堆栈的转储、做内存和 CPU 的 Profiling 等 |
jconsole | 图形界面 | JMX 兼容的图形工具,用于监控 JVM 的基本情况,查看 MBean |
jstat | 命令行 | JVM 统计监控工具,附加到一个 JVM 进程上记录JVM 的各种性能指标数据 |
jcmd | 命令行 | JVM 命令行调试工具,用于向 JVM 进程发送调试命令 |
jmap | 命令行 | JVM 堆内存分析工具,可以打印 JVM 进程对象的直方图、类加载统计,以及做堆转储操作 |
常用的第三方工具
MAT:Memory Analyzer tool的缩写,由 Eclipse 开发
Jprofiler:一款收费的 JVM 性能监控工具,可以很方便的跟 IDEA 进行集成
Arthas:阿里巴巴的开源的 Java 诊断工具,深受开发者喜爱,没有图形界面
模拟OOM,生成快照文件
@Override
public String demoTest() {
List<Byte[]> list = new ArrayList<>();
int count = 0;
while (true) {
list.add(new Byte[1024 * 1024]);
count++;
System.out.println(count);
}
// return "test";
}
生成快照文件有两个方式
- 启动项目时添加参数:把堆内存空间设置的小一点,这样循环没几次就OOM了
- -Xms50M 初始堆内存设置为50M
- -Xmx50M 最大堆内存设置为50M
- -XX:+HeapDumpOnOutOfMemoryError
- -XX:HeapDumpPath=具体路径 发生OOM 的话导出 Dump 到指定路径
整个 VM Optional:
-Xms50M -Xmx50M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=E:\oomlog
启动后调用接口报错:
- 如果未添加启动heap oom 的文件路径参数,可通过以下操作:
jmap -dump:format=b,file=E:\heap_dump_2.hprof 21196
问题定位
在指定目录下生成了java_pid21196.hprof文件
对于导出的快照文件,需要有一个工具打开来分析,这里选用的是 JProfiler,
安装教程点这里:Java JVM分析利器JProfiler 结合IDEA使用详细教程
快照记录的信息:
点击最大对象:
点击在图表中显示可以看到方法入口以及报错位置:
补充
- jmap -heap pid 展示pid的整体堆信息
根据打印的结果:默认存活区与eden比率=2:8
1)查看eden区:5.5M
2)两个存活区大小:都为5.5M
3)年轻代大小:16.5M
4)老年代大小:33.5M
6)最大堆内存大小:年轻代大小+老年代大小=50M
- jmap -histo pid 展示class的内存情况
说明:instances(实例数)、bytes(大小)、classs name(类名)。它基本是按照使用使用大小逆序排列的。
class name 对应的就是 Class 文件里的 class 的标识
- B 代表 byte
- C 代表 char
- D 代表 double
- F 代表 float
- I 代表 int
- J 代表 long
- Z 代表 boolean
- 前边有 [ 代表数组, [I 就相当于 int[]
- 对象用 [L+ 类名表示
只知道它占用了那么大的内存,但不知道由什么对象创建的。下一步需要将其他dump出来,使用内存分析工具进一步明确它是由谁引用的、由什么对象。
- jstat -gcutil 21196 5000
#其中21196为进程号,5000是指每5秒(5000毫秒)输出一次
查看gc频率的命令
- O代表老年代占用率
- FGC是FullGC次数
- FGCT是fullGC时间