探究JVM内存泄露

WEB 服务总是莫名其妙的运行一段时间后 JVM 直接 OutOfMemory 错误,内存泄漏的问题不容易查找,本文就一些查找内存泄露基本知识做个总结,未涉及到具体案例的分析。

1          JVM 内存异常的数据显示
1.1        java.lang.OutOfMemoryError: PermGen space 异常的例子

 

Heap 
PSYoungGen       total 44928K, used 916K [0x4e3c0000, 0x50fe0000, 0x51b10000) 
  eden space 44736K, 2% used [0x4e3c0000,0x4e4a5318,0x50f70000) 
  from space 192K, 0% used [0x50f70000,0x50f70000,0x50fa0000) 
  to  space 192K, 0% used [0x50fb0000,0x50fb0000,0x50fe0000) 
PSOldGen         total 453312K, used 125529K [0x32910000, 0x4e3c0000, 0x4e3c0000)
  object space 453312K, 27% used [0x32910000,0x3a3a6498,0x4e3c0000) 
PSPermGen       total 65536K, used 65535K [0x2e910000, 0x32910000, 0x32910000) 
  object space 65536K, 99% used [0x2e910000,0x3290fff8,0x32910000)

permanent space 持久空间 用于类和方法对象的存储。 spring  AOP 时使用 CBLIB 会动态产生很多类,当类太多,超过 MaxPermSize 的时候,就会抛出此异常。 参数问题 可以设置 jvm 启动参数 : PermSize, MaxPermSize 。程序问题就要进行内存分析了,详见下文。

1.2        java.lang.OutOfMemoryError: Java heap space 异常的例子

 

Heap
PSYoungGen total 88320K, used 67673K [0x44880000, 0x4ba40000, 0x4ba40000)
eden space 61952K, 100% used [0x44880000,0x48500000,0x48500000)
from space 26368K, 21% used [0x48500000,0x48a96490,0x49ec0000)
to space 24512K, 16% used [0x4a250000,0x4a6283e0,0x4ba40000)
PSOldGen total 932096K, used 582090K [0x0ba40000, 0x44880000, 0x44880000)
object space 932096K, 62% used [0x0ba40000,0x2f2b2a78,0x44880000)
PSPermGen total 131072K, used 35124K [0x03a40000, 0x0ba40000, 0x0ba40000)
object space 131072K, 26% used [0x03a40000,0x05c8d330,0x0ba40000)

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  
  0.00   0.00  99.99  82.51  53.11   2409    1.205 10117 7250.393 7251.598
  0.00   0.00  83.42  82.55  53.10   2409    1.205 10118 7252.650 7253.855
  0.00   0.00  56.06  82.46  53.10   2410    1.205 10120 7254.467 7255.672
  0.00   0.00  32.11  82.55  53.10   2411    1.205 10121 7256.673 7257.877
  0.00   0.00  99.99  82.55  53.10   2412    1.205 10123 7257.026 7258.231
  0.00   0.00  76.00  82.50  53.10   2412    1.205 10124 7259.241 7260.446

这个数据显示 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

参数含义: 
S0
  Heap 上的 Survivor space 0 段已使用空间的百分比 
S1
  Heap 上的 Survivor space 1 段已使用空间的百分比 
E
  Heap 上的 Eden space 段已使用空间的百分比 
O
  Heap 上的 Old space 段已使用空间的百分比 
P
  Perm space 已使用空间的百分比 
YGC
 :从程序启动到采样时发生 Young GC 的次数 
YGCT
  Young GC 所用的时间 ( 单位秒 
FGC
 :从程序启动到采样时发生 Full GC 的次数 
FGCT
  Full GC 所用的时间 ( 单位秒 
GCT
 :用于垃圾回收的总时间 ( 单位秒 )

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
--------------------------------------
1:    427398    14458448 [I
2:    178798     6830216 [C
3:     50278     6668512 <constMethodKlass>
4:    179924     4318176 java.lang.String
5:     50278     4026648 <methodKlass>
6:     15244     3894200 [B
7:     47809     1773776 [Ljava.lang.Object;
...
Total 1645187    81806088

说明:

#instance 是对象的实例个数 
#bytes 
是总占用的字节数 
class name 
对应的就是 Class 文件里的 class 的标识 
B 
代表 byte
C
 
代表 
char
D
 
代表 
double
F
 
代表 
float
I
 
代表 
int
J
 
代表 
long
Z
 
代表 
boolean
前边有 [ 代表数组, [I 就相当于 int[]

对象用 [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    

 

 

http://blog.csdn.net/ajian005/article/details/6454660

猜你喜欢

转载自guobin6125.iteye.com/blog/1408500
今日推荐