一次使用 Eclipse Memory Analyzer 分析 Tomcat 内存溢出

最近,线上生产系统忽然频繁的 JVM 内存报警!但本系统近期内并无上线改动!php

为了能查清内存报警的缘由,使用 Eclipse Memory Analyzer tool(MAT)对 JVM Dump 文件进行了分析!java

1. 生成 dump 文件eclipse

用 jmap 生产 dump 文件ide

jmap -dump:format=b,file=HeapDump.bin <pid>

2. MAT 安装与介绍this

下载地址:http://www.eclipse.org/mat/downloads.phpspa

1_20150209180326.jpg

经过 MAT 打开 dump 出来的内存文件,打开后以下图:orm

1_20150209180332.jpg 1_20150209180338.jpg

Histogram 能够列出内存中的对象,对象的个数以及大小。对象

Histogram 以下图:blog

Objects:类的对象的数量。
Shallow size:就是对象自己占用内存的大小,不包含对其余对象的引用,也就是对象头加成员变量(不是成员变量的值)的总和。
Retained size:是该对象本身的 shallow size,加上从该对象能直接或间接访问到对象的 shallow size 之和。换句话说,retained size 是该对象被 GC 以后所能回收到内存的总和。
ip

咱们发现 ConcurrentHashMap 类的对象占用了不少空间。

1_20150209180345.jpg

Leak Suspects 以下图:

从那个饼图,该图深色区域被怀疑有内存泄漏,能够发现整个 heap 2G 内存,深色区域就占了 98%。后面的描述,说明内存被一个实例占用了大量内存,并指出 system class loader 加载的"java.util.concurrent.concurrentHashMap$Segmen[]"实例的内存中汇集(消耗空间),并建议用关键字"java.util.concurrent.concurrentHashMap$Segmen[]"进行检查。因此,MAT 经过简单的报告就说明了问题所在。

1_20150209180403.jpg

Dominator Tree 以下图:>

咱们逐层打开 concurrentHashMap 的内存结构,发现 Key 很是多,而且最底层的 String 长度很大!

幸运的是该系统的下游也是咱们负责的系统,猜想 concurrentHashMap 应该是 RPC 调用返回回值待处理的内存存储,正常状况这个 String 的长度不很大。仔细查看, String 里包含了多了不少详细的异常描述信息,以前是没有的。

1_20150209180411.jpg

排查下游系统代码,发如今返回异常时,与以前异常抛出有所不一样:

try {
} catch(Exception e) {
    throw e;
}
 
...
 
try {
} catch(Exception e) {
    throw new Exception("xxxx", e);
}
 
// 返回伪代码
response(e.getMessage);

就是有这些许的不一样,咱们看下源代码:

public Throwable(String message, Throwable cause) {
    fillInStackTrace();
    detailMessage = message;
    this.cause = cause;
}
 
public Throwable(Throwable cause) {
    fillInStackTrace();
    detailMessage = (cause==null ? null : cause.toString());
    this.cause = cause;
}
 
public String getMessage() {
    return detailMessage;
}

当没有 message,message = cause.toString(),因此就形成了返回大量没必要要的异常信息,从而影响了上游系统!

参考:

http://tivan.iteye.com/blog/1487855


—————————— 本文同步发布于 ZHANGSR 个人我的博客  ——————————

相关文章
相关标签/搜索