我注意到我的应用程序中存在一种奇怪的现象。我将对象提交到服务器后将其存储在Hashmap中,并在响应到达时将其删除。
我最近注意到跑步后性能非常慢。检查后,我发现内存使用率保持在4GB,然后下降到小于1 GB。我怀疑它正在清理很多对象,这就是性能变得如此糟糕的原因。
所以问题是为什么Java收垃圾收集这么晚了?也就是说,为什么要等到堆满了然后再进行垃圾收集呢?不应该定期收集垃圾。
存储在HashMap中的对象就是在那个时候创建的,也就是说它们不会长久存在。
这是在Linux(RHEL),Oracle JVM HotSpot 7. 64位上。 4核心。这就是应用程序的运行方式:
java -jar -Xmx4g prog.jar
注意:我已经看到了这一点:Tuning garbage collections for low latency但是现在我想了解为什么GC需要这么长时间才能启动?
答案 0 :(得分:3)
听起来你有两个问题之一:
我会把你的年轻一代调整得更大。请参阅Generational Garbage Collection并查看各种类型的代。
答案 1 :(得分:1)
所以问题是为什么Java收垃圾收集这么晚了?也就是说,为什么要等到堆满了然后再进行垃圾收集呢?不应该定期收集垃圾。
您正在使用“吞吐量”垃圾收集器,这就是收集器的行为方式。它旨在通过最小化执行垃圾收集所花费的CPU时间百分比来最大化系统吞吐量。它通过等待堆(或更确切地说,新对象空间)已满的简单策略来实现。在所有条件相同的情况下,最有效的是:
(要了解原因,您需要了解复制收藏家的工作方式的技术细节......)
当然,这意味着你会有重大的停顿。
如果您想要低延迟,则需要使用其他收集器。但是,这会导致更多的实际CPU时间用于垃圾收集......以及其他与GC相关的开销。
如果您遇到很多重大停顿,那么空间的相对大小也可能存在问题。但是在你弄清楚相关参数之前,建议你打开GC记录,试着找出造成暂停的原因和频率。
答案 2 :(得分:0)
这只是因为除非堆已满,否则默认的GC不会启动。
JVM选择的默认垃圾收集器是Parallel GC。它的目标是在尽可能短的停止世界暂停期间释放尽可能多的内存。除非伊甸园已满,否则它不会在年轻一代开始。同样,除非Tenured已满,否则它不会在老一代开始。
如果要定期清理内存,可以切换到CMS。只需使用标志-XX:+UseConcMarkSweepGC
即可。但是,这将意味着您的应用程序的一些开销。这是让GC定期运行而不暂停应用程序的成本。
所以,总结一下:
并行GC暂停应用程序,仅在没有其他选择时启动
CMS并发运行而不会暂停您的应用程序,但有一些开销
来源:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html