文章目录
一. 内存溢出模拟以及导出内存映像文件
- 文末贴详细代码,这里给出部分代码:
@RestController
@RequestMapping("memory")
public class MemoryController {
private List<User> userList = new ArrayList<User>();
private List<Class<?>> classList = new ArrayList<Class<?>>();
/**
* 1. 堆内存溢出
* 循环往userList 里增添对象,因为 MemoryController对象不会回收,则userList肯定也不会回收
* jvm参数:-Xmx32M -Xms32M
* */
@GetMapping("/heap")
public String heap() {
int i=0;
while(true) {
userList.add(new User(i++, UUID.randomUUID().toString()));
}
}
/**
* 1. 非堆内存溢出
* 产生大量的类对象填满方法区
* jvm参数:-XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M
* */
@GetMapping("/nonheap")
public String nonheap() {
while(true) {
classList.addAll(Metaspace.createClasses());
}
}
}
1.1 自动导出内存映像文件
内存溢出时自动导出 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./
- 配置jvm参数并启动
其中,-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./
表示内存溢出时自动导出内存映像文件文件。 - 访问http://localhost:8080/memory/heap 接口会发现内存溢出。
- 在项目根目录下会发现自动导出的内存映像文件
住:这种自动导出的方式在生产环境中并不常用,因为有时候会影响性能以及卡顿问题,最好用 jmap -dump
导出
1.2 jmap -dump 导出内存映像文件
在上节的第2步之后,cmd窗口下分别运行:
jps -l // 打印虚拟机进程以及对应pid
jmap -dump:format=b,file=heap.hprof 16892 // 导出内存映像文件到当前目录
1.3. jmap -heap 命令显示堆信息
jmap -heap 命令显示堆的详细信息,比如使用哪种回收器、参数配置、分代状况等,结果注释如下:
C:\Users\libin\Desktop>jmap -heap 16892
Attaching to process ID 16892, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
using thread-local object allocation.
Parallel GC with 4 thread(s) // 使用 Parallel 并行收集器
Heap Configuration:
MinHeapFreeRatio = 0 //JVM最小空闲比率 可由-XX:MinHeapFreeRatio=<n>参数设置, jvm heap 在使用率小于 n 时 ,heap 进行收缩
MaxHeapFreeRatio = 100 //JVM最大空闲比率 可由-XX:MaxHeapFreeRatio=<n>参数设置, jvm heap 在使用率大于 n 时 ,heap 进行扩张
MaxHeapSize = 2095054848 (1998.0MB) //JVM堆的最大大小 可由-XX:MaxHeapSize=<n>参数设置
NewSize = 44040192 (42.0MB) //JVM新生代的默认大小 可由-XX:NewSize=<n>参数设置
MaxNewSize = 698351616 (666.0MB) //JVM新生代的最大大小 可由-XX:MaxNewSize=<n>参数设置
OldSize = 88080384 (84.0MB) //JVM老生代的默认大小 可由-XX:OldSize=<n>参数设置
NewRatio = 2 //新生代:老生代(的大小)=1:2 可由-XX:NewRatio=<n>参数指定New Generation与Old Generation heap size的比例。
SurvivorRatio = 8 //survivor:eden = 1:8,即survivor space是新生代大小的1/(8+2)[因为有两个survivor区域] 可由-XX:SurvivorRatio=<n>参数设置
MetaspaceSize = 21807104 (20.796875MB) //元空间的默认大小,超过此值就会触发Full GC 可由-XX:MetaspaceSize=<n>参数设置
CompressedClassSpaceSize = 1073741824 (1024.0MB) //类指针压缩空间的默认大小 可由-XX:CompressedClassSpaceSize=<n>参数设置
MaxMetaspaceSize = 17592186044415 MB //元空间的最大大小 可由-XX:MaxMetaspaceSize=<n>参数设置
G1HeapRegionSize = 0 (0.0MB) //使用G1垃圾收集器的时候,堆被分割的大小 可由-XX:G1HeapRegionSize=<n>参数设置
Heap Usage:
PS Young Generation //新生代堆粉笔情况
Eden Space: //Eden 区域
capacity = 7864320 (7.5MB)
used = 7864320 (7.5MB)
free = 0 (0.0MB)
100.0% used
From Space: // 其中一个Survivor区域
capacity = 1572864 (1.5MB)
used = 0 (0.0MB)
free = 1572864 (1.5MB)
0.0% used
To Space: // 另一个Survivor区域
capacity = 1572864 (1.5MB)
used = 0 (0.0MB)
free = 1572864 (1.5MB)
0.0% used
PS Old Generation //老生代区域分配
capacity = 22544384 (21.5MB)
used = 22228088 (21.19835662841797MB)
free = 316296 (0.30164337158203125MB)
98.59700757403706% used
13418 interned Strings occupying 1903808 bytes.
二. MAT 分析内存映像文件
MAT可以用于查找内存泄露以及查看内存消耗情况,具体就是可以查看每个类的使用情况以及内存占用情况,从而分析问题。
使用方式参考:Java程序内存分析:使用mat工具分析内存占用l
- 启动MAT并导入上章的 内存映像文件,默认会进入下面界面,主要使用圈出来的两个工具。
Histogram可以列出内存中的对象,对象的个数以及大小。
Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
Top consumers通过图形列出最大的object。
Leak Suspects通过MA自动分析泄漏的原因。
- Histogram 界面示例
Class Name : 类名称,java类名
Objects : 类的对象的数量,这个对象被创建了多少个
Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用
Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收到内存的总和
- Dominator Tree 界面示例
可以看出占用内存最大的 是User对象
延伸阅读:
Shallow heap & Retained heap解释