这是一个内存堆栈(作为高速缓存),其包含的只是一个静态的ConcurrentHashMap(CHM).
所有传入的HTTP请求数据都存储在此ConcurrentHashMap中.而且还有一个非同步调度过程中,从相同的ConcurrentHashMap取得数据,并将它们存储到数据库中后删除key.value.
该系统运行良好和平稳,但在以下条件才发现,内存得到了充分利用(2.5GB)和所有的CPU时间被送往执行GC:
-concurrent http命中1000/s
- 在15分钟内保持相同的并发命中
每次写入数据库时,异步进程都会记录CHM的剩余大小.CHM.size()保持在Min:300到Max:3500左右
我认为此应用程序存在内存泄漏.所以我使用Eclipse MAT来查看堆转储.运行可疑报告后,我从MAT获得了这些评论:
"org.apache.catalina.session.StandardManager" 通过 "org.apache.catalina.loader.StandardClassLoader @ 0x853f0280" 加载的一个实例占据2135429456(94.76%)字节.该存储器中的"$ java.util.concurrent.ConcurrentHashMap中段[]"通过""加载一个实例积累.
3,646,166 instances of java.util.concurrent.ConcurrentHashMap$Segment retain >= 2,135,429,456 bytes.
Run Code Online (Sandbox Code Playgroud)
和
Length # Objects Shallow Heap Retained Heap
0 3,646,166 482,015,968 >= 2,135,429,456
Run Code Online (Sandbox Code Playgroud)
我将上面的长度0转换为CHM内的空长度记录(每次调用CHM.remove()方法).它与数据库内的记录数一致,创建此转储时,数据库中有3,646,166条记录
奇怪的情况是:如果我暂停压力测试,堆内存中的利用率将逐渐降至25MB.这需要大约30-45分钟.我重新模拟了这个应用程序,曲线看起来类似于下面的VisualVM图:

继承人的问题:
1)这看起来像是内存泄漏吗?
2)每次删除调用remove(Object key, Object value)以<key:value>从CHM中删除a ,删除的对象是否获得GC?
3)这与GC设置有关吗?我添加了以下GC参数但没有帮助:
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:GCTimeRatio=19
-XX:+PrintGCTimeStamps
-XX:ParallelGCThreads=6
-verbose:gc
Run Code Online (Sandbox Code Playgroud)
4)非常感谢任何解决这个问题的想法!:)
新 5)可能因为我的所有参考都是难以参考的吗?我的理解是,只要HTTP会话结束,所有那些非静态的变量现在都可用于GC.
新注意我尝试用ehcache 2.2.0替换CHM,但是我遇到了相同的OutOfMemoryException问题.我想ehcache也在使用ConcurrentHashMap.
服务器规格:
-Xeon Quad内核,8个线程.
-4GB内存
-Windows 2008 R2
-Tomcat 6.0.29
Reu*_*ble 10
这个问题让我错了7天!最后我发现了真正的问题!以下是我尝试但未能解决OutOfMemory异常的任务:
- 使用concurrenthashmap更改为ehcache.(原来ehcache也在使用ConcurrentHashMap)
- 更改所有对Soft Reference的硬引用
- 根据Heinz M. Kabutz博士的建议,将AbstractMap与concurrnetHashMap一起使用
百万美元的问题真的是"为什么30-45分钟后,内存开始重新发布到堆池?"
实际的根本原因是因为还有其他东西仍然存在实际的变量会话,而罪魁祸首是tomcat中的http会话仍处于活动状态!因此,即使http会话已完成,但如果超时设置为30分钟,则tomcat会将会话信息保留30分钟,然后JVM才能进行GC会话.在将超时设置更改为1分钟作为测试后立即解决问题.
$tomcat_folder\conf\web.xml
<session-config>
<session-timeout>1</session-timeout>
</session-config>
Run Code Online (Sandbox Code Playgroud)
希望这会帮助那些有类似问题的人.
我认为你正在使用过多的 会话数据,这些 数据在内存中不能同时适应.试试这个:
编辑bin/setenv.sh或在Tomcat启动器上设置JVM参数的位置:
附加 -Dorg.apache.catalina.session.StandardSession.ACTIVITY_CHECK=true
例如
# Default Java options
if [ -z "$JAVA_OPTS" ]; then
JAVA_OPTS="-server -Djava.awt.headless=true -XX:MaxPermSize=384m -Xmx1024m -Dorg.apache.catalina.session.StandardSession.ACTIVITY_CHECK=true"
fi
Run Code Online (Sandbox Code Playgroud)编辑conf/context.xml,然后</Context>添加:
<Manager className="org.apache.catalina.session.PersistentManager"
maxIdleBackup="60" maxIdleSwap="300">
<Store className="org.apache.catalina.session.FileStore"/>
</Manager>
Run Code Online (Sandbox Code Playgroud)重新启动Tomcat,您的问题应该消失,因为它将使用文件系统存储您的会话.
我认为设置session-timeout = 1是一个解决办法掩盖问题的根源,并在你真正需要一个足够大的大多数应用程序无法使用session-timeout.我们(Bippo的),通常应用程序都有一个session-timeout的2880分钟,即2天.
1)这看起来像内存泄漏吗?
是的,如果应用程序不断将对象放入映射中并且从不删除它们,那么这很可能是内存泄漏。
2) 每次删除调用remove(Object key, Object value)从CHM中删除一个对象,该删除的对象是否会被GC?
仅当没有活动(正在运行)的线程引用对象时,对象才能被垃圾收集。地图只是一个引用该对象的地方。仍然可能有其他地方引用同一对象。但是将对象保留在映射中将阻止它被垃圾收集。
3)这与GC设置有关吗?
不; 如果一个对象被引用,它就不能被垃圾回收;你如何调整垃圾收集器并不重要。
| 归档时间: |
|
| 查看次数: |
24279 次 |
| 最近记录: |