Java - JVM - jmap 简介
-
概述
- 继续聊 jvm 命令行工具
-
背景
-
之前聊过一些简单的命令行工具
- jps
- 查看当前 java 进程
- jinfo
- 查看 java 运行参数
- 查看当前 相关系统变量
- jstat
- 查看 jvm 的 堆内存,gc 统计信息
- jps
-
如果我想查看堆内存里到底有什么, 有办法吗?
- 当然有啦
- jmap 为当前的堆内存打快照
- jhat 解析快照, 并以 httpserver 的形式, 对外发布
- 当然有啦
-
作为一个学渣, 之前这些东西, 我都得过且过, 或者压根不管他们存在不存在
- 就算存在, 也不耽误我写 bug
- 其实应该鼓起勇气, 跟随好奇心, 去看书, 去找各路学霸交流
-
-
环境
- OS
- win10
- Java
- 1.8.0_201
- demo
- Spring Boot
- 2.1.3
- Spring Boot
- shell
- win10 cmd
- OS
1. 准备
-
示例进程
- 随便起了个 spring-boot 的 webmvc 工程
- 写个 hello world 之类的就行
- 随便起了个 spring-boot 的 webmvc 工程
-
jps
- 获取进程的 pid
-
约定
- 后面只描述 本地执行 的结果
- jmap 其实可以远程执行, 这个有兴趣的同学自己去研究吧
- 后面只描述 本地执行 的结果
2. jmap
-
概述
- jmap 简介
-
jmap
- 展示工具
- 展示内容
- 堆内存
- 共享对象的内存映射
- 这块我目前不是很了解
- 展示方法
- 展示内容
- 展示工具
3. 命令使用
1. 共享对象映射
-
命令
>jmap 8944 Attaching to process ID 8944, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.181-b13 0x000000005f8a0000 52K C:\Program Files\Java\jdk1.8.0_181\jre\bin\management.dll 0x000000005f8b0000 68K C:\Program Files\Java\jdk1.8.0_181\jre\bin\nio.dll 0x000000005f8d0000 104K C:\Program Files\Java\jdk1.8.0_181\jre\bin\net.dll 0x000000005f8f0000 140K C:\Program Files\Java\jdk1.8.0_181\jre\bin\instrument.dll 0x000000005f920000 88K C:\Program Files\Java\jdk1.8.0_181\jre\bin\zip.dll 0x000000005f940000 164K C:\Program Files\Java\jdk1.8.0_181\jre\bin\java.dll 0x000000005f970000 60K C:\Program Files\Java\jdk1.8.0_181\jre\bin\verify.dll 0x000000005f980000 8840K C:\Program Files\Java\jdk1.8.0_181\jre\bin\server\jvm.dll 0x0000000060230000 840K C:\Program Files\Java\jdk1.8.0_181\jre\bin\msvcr100.dll ...
-
内容
- JVM version is 25.181-b13
- jvm 版本
- 0x000000005f8a0000
- 共享对象所映射的 内存地址
- 52K
- 共享对象的大小
- C:\Program Files\Java\jdk1.8.0_181\jre\bin\management.dll
- 共享对象在本地的路径
- JVM version is 25.181-b13
-
共享对象
-
疑问1
- 这玩意是干啥的, 之前听人讲 jvm 内存, 印象中没人提起过
- 可能是我之前没认真听讲吧...
- 这玩意是干啥的, 之前听人讲 jvm 内存, 印象中没人提起过
-
又是一些疑问
- 启动 java 程序, 每次都要启动 jvm, 加载系统类
- 既然是这样的话, 有没有什么办法, 可以让这些老熟人能够区别于通用的类, 加载得更快
- 如果在一个环境下, 启动多个 jvm
- 如果每个 jvm 都把这些类加载一遍, 是不是又费时又费力
- 有没有办法, 把这个进程加快
- 启动 java 程序, 每次都要启动 jvm, 加载系统类
-
共享对象
-
引入时间
- java 1.5
-
目的
- 加快特定类型的加载
- 特别是对 小型 java 应用, 效果拔群
- 并对这些特定类型, 提供 跨 jvm 共享
- 加快特定类型的加载
-
机制
- 文件机制
- linux
- classes.jsa 与 classeslist
- 将多个类放入 classes.jsa 中
- 将具体的类名, 记录在 classeslist 中
- classes.jsa 与 classeslist
- win
- 老实说, 我还没找到具体的机制
- 但是从结果来看, 类型都放到了 dll 文件里
- linux
- 加载机制
- 这块暂时也没弄太明白
- 内存机制
- 这个我也暂时没弄明白
- 比如在 jvm 内存中的哪个位置
- 不过按理说, 应该会在 meta space 那块
- 而且通常, 这些 公用的类型, 应该也是 只读 的
- 这个我也暂时没弄明白
- 文件机制
-
其他
- 当然这个并不是重点, 看不懂也没关系
-
-
2. 堆内存概况
-
命令
>jmap -heap 8944 Attaching to process ID 8944, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.181-b13 using thread-local object allocation. Parallel GC with 10 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 17163091968 (16368.0MB) NewSize = 357564416 (341.0MB) MaxNewSize = 5721030656 (5456.0MB) OldSize = 716177408 (683.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 268435456 (256.0MB) used = 26775152 (25.534774780273438MB) free = 241660304 (230.46522521972656MB) 9.974521398544312% used From Space: capacity = 44564480 (42.5MB) used = 20312032 (19.371063232421875MB) free = 24252448 (23.128936767578125MB) 45.578972311580884% used To Space: capacity = 44564480 (42.5MB) used = 0 (0.0MB) free = 44564480 (42.5MB) 0.0% used PS Old Generation capacity = 468189184 (446.5MB) used = 15216480 (14.511566162109375MB) free = 452972704 (431.9884338378906MB) 3.2500708089830628% used 16826 interned Strings occupying 2198488 bytes.
-
解释
-
Parallel GC with 10 thread(s)
- 使用了 Parallel GC
- 使用了 10 个线程
-
Heap Configuration
- 堆配置
- 具体配置我就不细说了
- 堆配置
-
Heap Usage
- 略
-
16826 interned Strings occupying 2198488 bytes.
- 有 16826 个内置字符串
- 占用了 2M 的空间
-
-
疑问
- NewRatio
- 完全不懂
- SurvivorRatio
- 完全不懂
- CompressedClassSpaceSize
- 它不是 meta space 的一部分吗, 怎么比 meta 还大
- internal Strings
- 这块老实说, 我也不是很懂...
- NewRatio
3. 析构信息概述
-
命令
>jmap -finalizerinfo 8944 Attaching to process ID 8944, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.181-b13 Number of objects pending for finalization: 0
-
解释
- Number of objects pending for finalization: 0
- 有 0 个对象, 即将被析构
- Number of objects pending for finalization: 0
4. 类型统计
-
命令
>jmap -histo 8944 num #instances #bytes class name ---------------------------------------------- 1: 370446 47173928 [C 2: 13190 16507488 [B 3: 237789 5706936 java.lang.String 4: 3867 3913304 [I 5: 56074 2945096 [Ljava.lang.String; 6: 42757 1368224 java.io.File 7: 32465 1298600 java.util.LinkedHashMap$Entry ... ...
-
解释
-
排列顺序
- 默认是按照 bytes 的 降序 来做排列的
-
1: 370446 47173928 [C
- 1
- 编号为 1
- 370446
- 实例个数, 为 370446 个
- 47173928
- 实例占据内存空间, 为 47M
[C
- 类型名为
[C
- 类型名为
- 1
-
-
继续解释
- live
- -histo 还可以跟 live 参数
- -histo:live
- 结果会有比较大的差别
- live 只展现当前 存活 的对象
- -histo 还可以跟 live 参数
- live
-
疑问
[C
- 类型
- 有的类型, 不是直接显示的类型, 而是显示的这个...
- 我现在也是 蒙圈的, 后续再讲吧
- 类型
5. 输出 dump 文件
-
命令
# 1. 这次就带上 live 了 # 2. 写作中途电脑又重启了, 所以 pid 换了 >jmap -dump:live,format=b,file=dump.txt 14504 Dumping heap to E:\dump.txt ... Heap dump file created
-
解释
- 选项
- -dump:live
- dump 当前 java 进程的堆内存
- format=b
- 使用 hprof 二进制格式
- file=dump.txt
- 指定输出文件名, 为 dump.txt
- 分割
- 使用 , 分割选项
- -dump:live
- 选项
-
结果
- 产生了一个 dump 文件
- 这个后续再讲吧...
- 产生了一个 dump 文件
ps
-
ref
- 'Shared Object Memory' vs 'Heap Memory' - Java
- 引出了第二个 ref
- what is shared objects file?
- 引出了 第三个 ref
- Class Data Sharing
- 类型数据共享
- 官方文档
- 简单描述了下机制
- 感兴趣的童鞋, 可以自己了解, 这个和我关系不大, 我就不多说了
- 类型数据共享
- jmap
- 官方文档
- Java-String.intern的深入研究
- internal Strings 的相关研究
- 有空的同学可以看一看
- internal Strings 的相关研究
- jmap命令详解----查看JVM内存使用详情
- 博主讲得还不错
- 'Shared Object Memory' vs 'Heap Memory' - Java
-
后续
- jhat
- 可视化工具
- 命令行工具讲完了, 就该讲用户喜闻乐见的可视化工具了
- jvm 内存的相关知识
- 之前那个 模糊的类型, 最好也了解一下
尽量尝试解释清楚; 自己校对能力有限, 如果有错误欢迎指出