我正在努力为我的JVM获得正确的设置。
以下是用例: Tomcat正在处理请求(300req / s)。但它们非常快(键值查找)所以我没有任何性能问题。一切都会正常工作,直到我必须刷新它每3小时服务一次的数据。你可以想象我有一个很大的HashMap,我只是在做查找。在重新加载数据期间,创建一个临时的HashMap然后我交换它。我需要加载相当多的数据(每次内存大约800MB)。
我在那些负载期间遇到的问题Tomcat不时停止响应。 最初的问题是促销失败和FullGC,但我通过调整设置解决了这些问题。
正如您可能已经注意到,当CMS收集器启动时,我已经减少了值。我不会再获得任何促销失败或类似的东西。年轻一代相当小,可以快速进行小型收藏。我增加了SurvivorRatio,因为所有的请求对象都很年轻,不应该自动提升到老一代。(数据正在加载)。
但是在数据加载期间我仍然在Tomcat中看到503错误。在gc.log中,我的次要集合在此过程中开始变慢。与毫秒相比,它们现在只需几秒钟。我已经尝试减慢加载过程以使GC喘息,但我似乎没有工作...... 当我达到老一代的能力时,问题尤其成问题。 CMS启动,释放内存,然后分配非常慢。我不再在gc.log中看到任何错误。 我能做些什么不同的事情?我知道碎片可能是一个问题,但我没有得到促销失败。该机器是一个8核服务器。减少GCThread的数量是否有意义?为数据加载线程设置一个较低的线程优先级是否有意义?
有没有办法在后台定期启动CMS收集器?正在交换的数据实际上可以立即被垃圾收集。
我愿意接受任何建议!
以下是我的JVM设置。
-Xms14g
-Xmx14g
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+AlwaysPreTouch
-XX:MaxNewSize=256m
-XX:NewSize=256m
-XX:MaxPermSize=128m
-XX:PermSize=128m
-XX:SurvivorRatio=24
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=88
-XX:+UseCompressedStrings
-XX:+DisableExplicitGC
JDK 1.6.33 Tomcat 6
gc.log片段:
第7行数据加载开始
第20行停止
答案 0 :(得分:2)
查看附加的日志并看到次要GC时间的巨大增长使我相信您的计算机受到来自JVM之外的其他进程的极大负载。
我的理由是,当您的次要GC发生时,所有应用程序线程都会停止。因此,您的应用程序所做的任何事情都不应该影响次要GC时间,因为您的新基因大小不变。
但是,如果在此期间机器上的其他进程有很多负载,GC线程将竞争执行时间,您可能会看到此行为。
您可以在数据加载运行时检查其他进程的CPU使用情况吗?
编辑:再看一下日志,我想出了另一种可能的解释。
目标幸存者空间似乎已满(ParNew降至每个“慢”GC正好10048K)。这意味着对象被直接提升为旧的gen,这可能会减慢这种速度。我会尝试增加新一代的规模并降低幸存者的比例。甚至可能尝试在没有设置新的gen大小或幸存率的情况下运行,看看JVM如何设法优化它(尽管要注意JVM通常在优化这样的突发方面做得不好)。
答案 1 :(得分:1)
你的负载持续大约90s并且每1s左右被GC中断但是你有一个14G的堆,它的稳态占用(假设周围的日志线是稳定的状态)只有大约5G,这意味着你有很多内存浪费。我认为前面的答案看起来是正确的(基于所提供的数据),当它说你的幸存者空间太小时。如果合理的话除了查找剩下的时间之外什么都没有,那么一个完全合理的策略就像是
这里的重点是在加载阶段尝试完全避免年轻的收集。但是,暂停阈值为0意味着之前的版本可能会在终身,并且您最终会看到一个可能很长的集合来清理它。另一个选择可能是反过来,并且已经足够大,足以容纳2-3个版本的数据,并且其余的就是为了尽量减少年轻收集的频率并尽快收集终身帮助。
最有效的方法取决于应用程序在剩下的时间内做了什么。
cms触发器对于大堆btw来说似乎相当高,如果你只开始收集88%那么它是否有时间在强制fullgc之前完成工作?我想如果你实际上大部分时间都做了很少的分配,那可能会很安全。