Java内存泄漏案例

来源:互联网 发布:游族网络2017定增 编辑:程序博客网 时间:2024/06/16 11:12
目录
[隐藏]
  • 1问题现象
  • 2问题解决过程
    • 2.1查看tomcat的进程号(jps或者ps命令都可以)
    • 2.2检查垃圾回收情况
    • 2.3导出heap.bin
    • 2.4heap.bin分析
      • 2.4.1查看统计信息
      • 2.4.2查看泄露的代码
      • 2.4.3检查代码中loggers变量的泄露
      • 2.4.4解决方法

1.问题现象

某系统在运行几天之后,变得非常的慢,所有功能几乎不能用,偶尔会报OutOfMemory。

2.问题解决过程

注:

  • 系统运行在linux环境
  • 文中涉及命令:jps、jstat、jmap命令都在xxx/java/jdk1.5.0_15/bin路径下,且要用root用户执行。
    • jps   — 显示系统中的java进程信息
    • jstat — 对垃圾回收过程进行采样
    • jmap  — 导出java内存到二进制文件

2.1.查看tomcat的进程号(jps或者ps命令都可以)

root:/xxx/java/jdk1.5.0_15/bin # ./jps
18830 Jps
28360 Bootstrap
root:/xxx/java/jdk1.5.0_15/bin # ps -ef | grep java
root     28360     1  1 Oct25 ?        07:12:12 /xxx/java/java/bin/java -Djava.util.logging.config.file=/home/zxin10/tomcat/conf/logging.properties -Xms800m -Xmx800m -XX:PermSize=128m -XX:MaxPermSize=512m -Xdebug -Xrunjdwp:transport=dt_socket,address=8348,server=y,suspend=n -Djava.endorsed.dirs=/home/zxin10/tomcat/common/endorsed -classpath :/home/zxin10/tomcat/bin/bootstrap.jar:/home/zxin10/tomcat/bin/commons-logging-api.jar -Dorg.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false -Dcatalina.base=/home/zxin10/tomcat -Dcatalina.home=/home/zxin10/tomcat -Djava.io.tmpdir=/home/zxin10/tomcat/temp org.apache.catalina.startup.Bootstrap start
root     19028 16771  0 14:06 pts/0    00:00:00 grep java

2.2.检查垃圾回收情况

root:/xxx/java/jdk1.5.0_15/bin # ./jstat -gcutil 28360 500 0
S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
4.46   0.00  58.34  79.17  72.21   4966  116.404  1146 2764.054 2880.458
4.46   0.00  58.87  79.17  72.21   4966  116.404  1146 2764.054 2880.458
4.46   0.00  58.87  79.17  72.21   4966  116.404  1146 2764.054 2880.458
4.46   0.00  58.87  79.17  72.21   4966  116.404  1146 2764.054 2880.458
4.46   0.00  66.27  79.17  72.21   4966  116.404  1147 2764.054 2880.458
4.46   0.00  66.27  79.17  72.21   4966  116.404  1147 2764.054 2880.458
4.46   0.00  66.27  79.17  72.21   4966  116.404  1147 2764.054 2880.458
4.46   0.00  66.27  79.17  72.21   4966  116.404  1147 2764.054 2880.458
4.46   0.00  66.27  79.17  72.21   4966  116.404  1147 2764.054 2880.458
4.46   0.00  66.27  79.17  72.21   4966  116.404  1147 2764.054 2880.458
0.00   0.00   5.00  79.98  72.22   4966  116.404  1148 2767.206 2883.610
0.00   0.00   5.00  79.98  72.22   4966  116.404  1148 2767.206 2883.610
0.00   0.00   5.00  79.98  72.22   4966  116.404  1148 2767.206 2883.610

jstat命令中:

28360 — tomcat的进程号

500  — 采样间隔,单位毫秒

    — 采样次数,0表示一直进行采样

采样数据中:S0、S1、E共同组成Young区。

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 — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒)

一次YGC,会对Young区(S0、S1、E)进行一次垃圾回收。

一次FGC,会对Young区、Old区进行垃圾回收。

但是,看到的采样数据中,进行了2次FGC(红色部分中的蓝色部分),但是Old区并没有被回收,大体说明:Old区的内存几乎不会被回收,存在泄露。

2.3.导出heap.bin

在系统慢时的内存数据heap.bin进行导出。
./jmap -histo 980
可以简单的查看内存状况

该命令执行的时候,会导致jvm假死,所以现场环境谨慎使用。有时候这个命令不能执行成功,多执行几次。(不成功原因:jvm繁忙之类)
root:/xxx/java/jdk1.5.0_15/bin # ./jmap -heap:format=b  28360
28360 — tomcat的进程号

成功之后在此目录下,会生成heap.bin。

2.4.heap.bin分析

将这个文件下载到windows的本机环境,使用JVMmat进行分析。

2.4.1.查看统计信息

下图红色部分表明Logger对象异常多。

  • ArrayList、Object[]多,很可能是Logger对象多引起,因此着重检查本系统相关代码。

memory-leak-jvmmat-1

2.4.2.查看泄露的代码

memory-leak-jvmmat-2

点击上图的按钮Leak Suspects,出现泄露的界面:

memory-leak-jvmmat-3

点击Details链接后,可以看到泄露的对象:

memory-leak-jvmmat-4

2.4.3.检查代码中loggers变量的泄露

LoggerFactory.java中:

protected void addLogger(Logger logger){    if (null != logger)    {        synchronized (this.loggers)        {            this.loggers.add(logger);        }        for (Outputter o : this.outputters)        {            logger.addOutputter(o);        }    }}

其中

  • loggers是一个final对象,会永久存储。
  • 而函数的入参logger是临时对象,生命周期会很快结束。

把一个临时变量永久保存,就出现内存回收不了,内存泄露的问题。

2.4.4.解决方法

  1. 直接注释掉 this.loggers.add(logger);
  2. 限制加入loggers集合的logger对象的数目即可


共享协议:署名-非商业性使用-相同方式共享 3.0 Unported 许可协议 
声明:未作说明,则本文为智昊的空间原创。转载务必注明出处。 
注意:转载须保留全文,如需修改请 联系作者。 
本文永久地址:http://zhihao.info/sd/programm-language/java/one-java-memory-leak-solution/

原创粉丝点击