考虑以下HashMap.clear()代码:
/**
* Removes all of the mappings from this map.
* The map will be empty after this call returns.
*/
public void clear() {
modCount++;
Entry[] tab = table;
for (int i = 0; i < tab.length; i++)
tab[i] = null;
size = 0;
}
Run Code Online (Sandbox Code Playgroud)
看来,对象的内部数组(table)Entry永远不会收缩.因此,当我向地图添加10000个元素时,在该调用之后map.clear(),它将在其内部数组中保留10000个空值.所以,我的问题是,JVM如何处理这个数组,因此,HashMap内存是否有效?
与任何内存管理问题一样,这是一个漫长的故事,所以绑定.
我们的应用程序一直存在一些内存管理问题,因此我一直在尝试分析应用程序以了解问题所在.我今天早些时候看过这个帖子:
...这似乎跟我在剖析器中看到的一样.基本上,如果我使用Jmeter的一堆用户点击应用程序,它会长时间保留在堆内存中,最终直到会话开始到期.然而,与该线程中的海报不同,我有源代码,并且可以选择尝试使用Tomcat实现持久状态会话,这是我今天一直在尝试做的事情,但成效有限.我认为这是一些我缺少的配置设置.这是我在context.xml中的内容:
<Manager className='org.apache.catalina.session.PersistentManager'
saveOnRestart='false'
maxActiveSessions='5'
minIdelSwap='0'
maxIdleSwap='1'
maxInactiveInterval='600'
maxIdleBackup='0'>
<Store className='org.apache.catalina.session.FileStore'/>
</Manager>
Run Code Online (Sandbox Code Playgroud)
在web.xml中我有这个:
<session-config>
<session-timeout>
10
</session-timeout>
</session-config>
Run Code Online (Sandbox Code Playgroud)
理想情况下,我希望会话在一小时内超时,但出于测试目的,这很好.现在,在玩了一些东西并最终进入这些设置后,我正在观看分析器中的应用程序,这就是我所看到的:

正如您在图像中看到的那样,我已经添加了一些注释.这是围绕问号圈出的部分,我真的不了解其中的任何事情.您可以看到我在几个不同的点使用Jconsole的"执行GC"按钮,您可以在图表中看到我使用Jmeter的许多客户端访问应用程序的部分.
如果我没记错的话(我必须回去并确实记录下来),在我实现持久状态之前,GC按钮在清除堆时不会做太多.这里奇怪的是,我似乎必须为这个持久状态手动运行GC以实际帮助任何事情.
或者,这只是一个简单的内存泄漏情况吗?今天早些时候,我进行了堆转储并将其加载到Eclipse Memory Analyzer工具中,并使用了"检测泄漏"功能,所有这一切都强化了这是一个会话大小问题的理论; 它检测到的唯一泄漏是在java.util.concurrent.ConcurrentHashMap $ Segment中引导我进入这个线程内存完全被Java ConcurrentHashMap使用(在Tomcat下)
这让我觉得这不是实际泄漏的应用程序.
其他相关细节: - 暂时在我的本地机器上运行/测试.这就是所有这些结果的来源. - 使用Tomcat 6 - 这是一个JSF2.0应用程序 - 我根据Tomcat文档添加了系统属性-Dorg.apache.catalina.STRICT_SERVLET_COMPLIANCE = true
所以,我想这里有几个问题:1.我是否正确配置了这个?2.是否有内存泄漏?3.此内存配置文件中发生了什么?它(相对)正常吗?
提前致谢.
UPDATE
所以,我尝试了肖恩的提示,并找到了一些新的有趣的东西.
会话侦听器运行良好,并且在分析此场景方面发挥了重要作用.还有一件事,我忘了提到的是应用程序的负载只是被单个页面混淆了,它在几乎可笑的比例上达到了功能复杂性.因此,在测试中,我有时会瞄准该页面,有时我会避开它.所以在我的下一轮测试中,这次使用会话监听器我发现了以下内容:
1)使用几十个客户端点击应用程序,只需访问一个简单的页面.我注意到会话在指定的时间限制之后都按预期发布,并且内存已经释放.同样的事情与少数客户完美配合,对于复杂的情况,点击"大"页面.
2)接下来,我尝试使用复杂的用例,使用几十个客户端来访问应用程序.这一次,发起的会议比预期多了几十个.似乎每个客户都在一到三个会话之间启动.在会话到期时间之后,释放了一点内存,但根据会话监听器,只有大约三分之一的会话被销毁.但是,与此相反,实际包含会话数据的文件夹是空的.大多数使用的内存也被保留.但是,在运行压力测试一小时后,垃圾收集器就会运行,一切都恢复正常.
所以,后续问题包括:
1)为什么在简单的情况下可以正确处理会话,但是当事情变得紧张时,它们会被正确管理?Session处理程序是否误报,或者使用JMeter以某种方式影响它?
2)为什么垃圾收集器等待一小时才能运行?是否有系统设置要求垃圾收集器必须在给定的时间范围内运行,或者是否有某些配置设置我缺少?
再次感谢您的继续支持.
更新2
只是一个简单的说明:更多地玩这个,我发现我得到关于实时会话数量的不同报告的原因是由于我使用持久会话; 如果我把它关闭,一切都按预期工作.它确实在Tomcat页面上表示持久会话,它是一个实验性功能.它必须是调用侦听器正在接收的会话事件,当人们非常期望它这样做时.
我们尝试将我们的应用程序从OC4J迁移到Tomcat 7.0.该应用程序适用于OC4J,但在tomcat中,当运行10个用户的负载测试时,性能会受到影响.我们得到这些错误,应用程序不再响应.
---java.lang.OutOfMemoryError: GC overhead limit exceeded
Exception in thread "ajp-bio-8009-exec-231" java.lang.OutOfMemoryError: GC overhead limit exceeded
Exception in thread "ContainerBackgroundProcessor[StandardEngine[Catalina]]" java.lang.OutOfMemoryError: GC overhead limit exceeded
Exception in thread "ajp-bio-8009-exec-236" java.lang.OutOfMemoryError: GC overhead limit exceeded
Exception in thread "ajp-bio-8009-exec-208" java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded
Exception in thread "Thread-33" java.lang.OutOfMemoryError: GC overhead limit exceeded
Exception in thread "ajp-bio-8009-exec-258" java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded
Run Code Online (Sandbox Code Playgroud)
我们试过了JAVA_OPTS="-Xms4096m -Xmx8192m.看起来我们仍然得到错误.请建议我们可以尝试的可能选项.. …