这是一个内存堆栈(用作缓存),仅由静态 ConcurrentHashMap (CHM) 组成。
所有传入的 HTTP 请求数据都存储在这个 ConcurrentHashMap 中。还有一个异步调度程序进程,它从同一个 ConcurrentHashMap 中获取数据,并在将它们存储到数据库后删除 key.value。
该系统运行良好且流畅,但只是发现在以下条件下,内存被充分利用(2.5GB)并且所有CPU时间都被用来执行GC:
-并发http点击量为1000/s
- 保持相同的并发点击 15 分钟
异步进程每次写入数据库时都会记录 CHM 的剩余大小。 CHM.size() 保持在 Min:300 到 Max:3500 左右
我认为这个应用程序存在内存泄漏。所以我使用 Eclipse MAT 查看堆转储。运行可疑报告后,我从 MAT 得到了以下评论:
由“org.apache.catalina.loader.StandardClassLoader @ 0x853f0280”加载的“org.apache.catalina.session.StandardManager”的一个实例占用2,135,429,456 (94.76%)字节。内存累积在“”加载的“java.util.concurrent.ConcurrentHashMap$Segment[]”的一个实例中。
3,646,166 instances of java.util.concurrent.ConcurrentHashMap$Segment retain >= 2,135,429,456 bytes.
and
Length # Objects Shallow Heap Retained Heap
0 3,646,166 482,015,968 >= 2,135,429,456
上面的长度 0 我将其翻译为 CHM 内的空长度记录(每次我调用 CHM.remove() 方法)。与数据库内的记录数一致,创建此转储时数据库内有 3,646,166 条记录
The strange scenario is: if i pause the stress test, the utilization in Heap Memory will gradually release down to 25MB.This takes about 30-45 minutes. i have re-simulate this application and the curves looks similar to the VisualVM Graph below:
问题如下:
1)这看起来像内存泄漏吗?
2)每次删除调用remove(Object key, Object value)
删除一个<key:value>
从 CHM 中,删除的对象会被 GC 吗?
3)这与GC设置有关吗?我添加了以下 GC 参数但没有帮助:
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:GCTimeRatio=19
-XX:+PrintGCTimeStamps
-XX:ParallelGCThreads=6
-verbose:gc
4)非常感谢任何解决此问题的想法! :)
NEW5)有可能因为我所有的引用都是硬引用吗?我的理解是,只要HTTP会话结束,所有那些非静态的变量现在都可以用于GC。
NEW注意我尝试用 ehcache 2.2.0 替换 CHM,但我遇到了相同的 OutOfMemoryException 问题。我想 ehcache 也在使用 ConcurrentHashMap。
服务器规格:
-Xeon 四核,8 线程。
-4GB内存
-Windows 2008 R2
- 雄猫6.0.29