WEB 服务总是莫名其妙的运行一段时间后 JVM 直接 OutOfMemory 错误,内存泄漏的问题不容易查找,本文就一些查找内存泄露基本知识做个总结,未涉及到具体案例的分析。
1 JVM 内存异常的数据显示
1.1 java.lang.OutOfMemoryError: PermGen space 异常的例子
Heap |
permanent space 持久空间 : 用于类和方法对象的存储。 spring 在 AOP 时使用 CBLIB 会动态产生很多类,当类太多,超过 MaxPermSize 的时候,就会抛出此异常。 参数问题 可以设置 jvm 启动参数 : PermSize, MaxPermSize 。程序问题就要进行内存分析了,详见下文。
1.2 java.lang.OutOfMemoryError: Java heap space 异常的例子
Heap |
eden space 使用率 100% ,总是被占满,参数问题 可以设置 jvm 启动参数 : Xms, Xmx 。程序问题就要进行内存分析了,详见下文。
1.3 查看 jvm 内存状态:
jstat -gcutil pid 1000 20
异常情况的例子
jstat -gcutil pid 1000 20
S0 S1 E O P YGC YGCT FGC FGCT GCT |
这个数据显示 Full GC 频繁发生。 |
正常情况的例子
S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031 0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031 0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031 0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031 0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031 0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031 |
参数含义: |
2 Dump 出内存
2.1 找出要 dump 的线程 pid
在 windows 下,使用 tasklist |
在 Linux 下,使用 ps –aux |
2.2 Dump 出内存使用详情
可以通过命令:
jmap -dump:file=a.hprof pid |
也可以通过 jconsole 的图形界面操作。
在命令行键入: jconsole |
Jconsole 打开后在造作下选择 dumpHeap, 输入参数 p0,p1;p0 表示 dump 出来的文件路径,后缀为 .hprof ; p1 设为 true ,表示只分析活着的对象。
3 使用内存分析工具
目前有很多用来分析 Java 内存对象的工具,如收费的工具有 jprofiler, 而像 Eclipse MAT 则是优秀的内存对象分析开源工具 . 它们对于分析内存溢出问题非常有用。以下是一个安装使用 Eclipse MAT 的简单例子。
3.1 装一个 Eclipse 的内存分析插件 MAT
http://download.eclipse.org/technology/mat/latest/update-site/
3.2 切换到 Memory Analysis 模式
3.3 通过 File > Open Heap Dump.... 查看 dump 出来的文件
4 JDK 自带的 JVM 查看分析工具 jps 、 jmap 、 jstat 、 jconsole
4.1 jps
Java 进程查看工具,实际上它和 Unix/Linux 上面的 ps 命令的功能差不多
4.2 jmap
jmap 是一个可以输出所有内存中对象的工具 .
* -dump:format=b,file=<filename> 转存堆内存到本地文件。
* -histo 打印堆里每个类的情况,包含内存占用大小、对象数量及完整类名。 VM 的内部类以 "*" 开头。
例子:
jmap -histo pid>a.log |
jmap -dump: file=a.hprof pid |
查看 a.log
num #instances #bytes class name |
说明: #instance 是对象的实例个数 对象用 [L+ 类名表示 |
4.3 jstat
jstat 是 vm 的状态监控工具,监控的内容有类加载、运行时编译及 GC 。
使用时,需加上查看进程的进程 id ,和所选参数。以下详细介绍各个参数的意义。
jstat -class pid: 显示加载 class 的数量,及所占空间等信息。
jstat -compiler pid: 显示 VM 实时编译的数量等信息。
jstat -gc pid: 可以显示 gc 的信息,查看 gc 的次数,及时间。其中最后五项,分别是 young gc 的次数, young gc 的时间, full gc 的次数, full gc 的时间, gc 的总时间。
jstat -gccapacity: 可以显示, VM 内存中三代( young,old,perm )对象的使用和占用大小,如: PGCMN 显示的是最小 perm 的内存使用量, PGCMX 显示的是 perm 的内存最大使用量, PGC 是当前新生成的 perm 内存占用量, PC 是但前 perm 内存占用量。其他的可以根据这个类推, OC 是 old 内纯的占用量。
jstat -gcnew pid:new 对象的信息。
jstat -gcnewcapacity pid:new 对象的信息及其占用量。
jstat -gcold pid:old 对象的信息。
jstat -gcoldcapacity pid:old 对象的信息及其占用量。
jstat -gcpermcapacity pid: perm 对象的信息及其占用量。
jstat -util pid: 统计 gc 信息统计。
jstat -printcompilation pid: 当前 VM 执行的信息。
除了以上一个参数外,还可以同时加上 两个数字,如: jstat -printcompilation 3024 250 6 是每 250 毫秒打印一次,一共打印 6 次,还可以加上 -h3 每三行显示一下标题。
例子:
jstat -gcutil pid 1000 20 |
4.4 jconsole
一个 java GUI 监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器 VM 。