jmap的使用以及内存溢出分析
jmap(java内存映像工具)
jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件)。还有几种方式获取dump文件:使用JVM参数选项-XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机在OOM异常出现之后自动生成dump文件,通过-XX:HeapDumpPath=path 设置dump文件路径(有时候dump文件比较大的时候可能无法自动导出,这时候就需要使用jmap -dump手动导出了);通过-XX.+HeapDumpOnCtrlBreak参数则可以使用[Ctrl]+[Break]键让虚拟机生成dump文件;或者在Linux系统下通过Kill -3命令发送进程退出信号,也能拿到dump文件。
jmap的作用并不仅仅是为了获取dump文件,它还可以查询finalize执行队列、Java堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。和jinfo命令一样,jmap有不少功能在Windows平台下都是受限的,除了生成dump文件的-dump选项和用于查看每个类的实例、空间占用统计的-histo选项在所有操作系统都提供之外,其余选项都只能在Linux/Solans下使用。官方文档地址
1.1、查看内存使用情况
[root@localhost /]# jmap -heap 9906 Attaching to process ID 9906, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.221-b11 using thread-local object allocation. Mark Sweep Compact GC Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = (944.0MB) NewSize = (20.0MB) MaxNewSize = (314.625MB) OldSize = (40.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = (20.MB) CompressedClassSpaceSize = (1024.0MB) MaxMetaspaceSize = 415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: New Generation (Eden + 1 Survivor Space): capacity = (18.0625MB) used = (5.0844MB) free = (12.0156MB) 28.046% used Eden Space: capacity = (16.0625MB) used = (4.8125MB) free = (11.1875MB) 28.681% used From Space: capacity = (2.0MB) used = (0.17188MB) free = (1.82812MB) 25.5938% used To Space: capacity = (2.0MB) used = 0 (0.0MB) free = (2.0MB) 0.0% used tenured generation: capacity = (40.0MB) used = (34.094MB) free = (5.90625MB) 86.734% used 31688 interned Strings occupying bytes.
1.2、查看内存中对象数量及大小
#查看所有对象,包括活跃以及非活跃的 jmap -histo <pid> | more #查看活跃对象 jmap -histo:live <pid> | more [root@localhost /]# jmap -histo:live 9906 | more num #instances #bytes class name ---------------------------------------------- 1: 72627 [C 2: 12052 [I 3: 3709 [B 4: 71294 java.lang.String 5: 14306 java.lang.reflect.Method 6: 8153 java.lang.Class 7: 26390 java.util.HashMap$Node 8: 23271 java.util.concurrent.ConcurrentHashMap$Node 9: 10490 [Ljava.lang.Object; 10: 5128 [Ljava.util.HashMap$Node; #对象说明 B byte C char D double F float I int J long Z boolean [数组,如[I表示int[] [L+类名 其他对象
1.3、将内存使用情况dump到文件中
#用法: jmap -dump:format=b,file=dumpFileName <pid> #示例 [root@localhost /]# jmap -dump:format=b,file=/cfile/dump.dat 9906 Dumping heap to /cfile/dump.dat ... Heap dump file created

1.4、通过jhat对dump文件进行分析
jvm的内存dump到文件中,这个文件是一个二进制的文件,不方便查看,可以借助于jhat工具进行查看。
#用法: jhat -port <port> <file> #示例 [root@localhost cfile]# jhat -port 8888 /cfile/dump.dat Reading from /cfile/dump.dat... Dump file created Thu Aug 19 11:31:02 CST 2021 Snapshot read, resolving... Resolving objects... Chasing references, expect 95 dots............................................................................................... Eliminating duplicate references............................................................................................... Snapshot resolved. Started HTTP server on port 8888 Server is ready.
打开浏览器进行访问:ip+端口(8888)

在最后面有OQL查询功能。

进入页面,输入下面语句查询字符串大于10000,点击Execute按钮,查询结果:
select s from java.lang.String s where s.value.length >= 10000

2、通过MAT工具对dump文件进行分析(官网)
MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I9geT1sO-1629355535351)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819114901423.png)]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
2.1、下载安装
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V7GQluyM-1629355535352)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819134930028.png)]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
运行独立版 Memory Analyzer 所需的最低 Java 版本是 Java 11 如果本地安装的JDK是更低版本的可以下载旧版本。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N61htSA0-1629355535352)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819140452413.png)]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
下载完成后解压MemoryAnalyzer-1.8.1.-win32.win32.x86_64.zip,解压后如图
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OU9rJl0G-1629355535353)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819140912714.png)]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
2.2、使用方式



查看对象以及它的依赖:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1WdBhgpu-1629355535355)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819141903120.png)]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
查看可能存在内存泄露的分析:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HSgNBWKc-1629355535355)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819142008106.png)]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
3、内存溢出的定位与分析
引起内存溢出的原因有很多种,常见的有以下几种:
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据。
- 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收。
- 代码中存在死循环或循环产生过多重复的对象实体。
- 使用的第三方软件中的BUG。
- 启动参数内存值设定的过小。
内存溢出在实际的生产环境中经常会遇到,如,不断的将数据写入到一个集合中,出现了死循环或者读取超大的文件等等,都可能会造成内存溢出。如果出现了内存溢出,首先我们需要定位到发生内存溢出的环节,并且进行分析,是正常还是非正常情况,如果是正常的需求,就应该考虑加大内存的设置,如果是非正常需求,那么就要对代码进行修改,修复这个bug。
3.1、模拟内存溢出
import java.util.ArrayList; import java.util.List; import java.util.UUID; public class TestJvmOutOfMemory {
public static void main(String[] args) {
List<Object> list = new ArrayList<>(); for (int i = 0; i < ; i++) {
String str = ""; for (int j = 0; j < 1000; j++) {
str += UUID.randomUUID().toString(); } list.add(str); } System.out.println("ok"); } }
为了更快的现实效果,这里使用Idea,设置执行的参数
#在每次发生内存溢出时,JVM会自动将堆转储,dump文件存放在-XX:HeapDumpPath指定的路径下。 -Xms8m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:

测试结果如下:

导入到MAT工具中进行分析
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N0a7OZ1h-1629355535357)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819144134395.png)]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
可以看到,有87.02%的内存由Object[]数组占有,所以比较可疑。
分析:已经有超过87%的内存都被它占有,这种情况是非常有可能出现内存溢出的
查看详情:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4da6MWYn-1629355535358)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819144329342.png)]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
可以看到集合中存储了大量的uuid字符串。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231529.html原文链接:https://javaforall.net
