我们有一个AIXWebsphere java7服务器,它使用一个非常大的内存表/数组对象,通常大小约为3.1 GB。对于该服务器,我们配置了-Xms=3072m和-Xmx=3840m(GC算法=gencon(。根据Dynatrace的说法,它一直工作正常,直到有一天GC时间突然从每分钟几毫秒增加到几秒。
巨大的对象通常会增长,因为只有少量的删除,没有更新,而是不断的插入。
尝试不同的方法,我们改进了GC时间(再次以毫秒为单位(,只是将-Xms更改为1024m。
有人知道什么原理允许这种改进吗?我在其他帖子中读到的恰恰相反。也就是说,增加Xms甚至将其与Xmx匹配将是最佳方法。
长时间的GC暂停可能是由于堆碎片需要压缩以将一些对象放置在堆的保有期区域。如果缓存对象占用了3.1 GB的最大3840米堆,那么在执行Java程序时,堆中几乎没有用于对象分配和删除的正常流的工作空间。由于Java对象必须在连续的内存空间中分配,因此,如果分配的某个对象在堆内存中没有足够大的连续空间,则需要进行压缩。压缩是一个相对漫长而缓慢的过程,它重新排列堆中对象的位置,以消除对象之间的小空间,并为新的分配创建一个大的连续区域(如对旧Windows系统上的硬盘驱动器进行碎片整理(。
坦率地说,我很惊讶像你描述的配置会表现得很好。除了";缓存对象";提到(可能这实际上是许多小对象的集合?(将有一组实现WebSphere运行时的长寿命对象的基线,这些对象通常需要超过100MB。然后,在任何Java系统中,都有一个恒定的对象创建和删除流程(通过垃圾收集(。一个典型的经验法则是调整堆的大小,以便在全局GC之后,保留区有50%的可用空间——全局GC之后任何低于20%的可用空间都会导致不希望的GC开销。
您是否在此配置中启用了详细GC日志记录?这是真正了解堆中发生了什么的唯一方法,并且了解这一点对Java系统的健康和性能至关重要。我们建议在所有Java系统、生产环境和测试环境中启用GC日志记录(通过在JVM参数中添加-verbose:GC(。IBMJava中GC日志记录的开销非常低,诊断价值非常高。
至于为什么设置-Xms1024可以提高性能,有几种可能性。
首先,这一变化可能并没有真正解决任何问题。你有一段时间没有看到GC长时间的暂停,然后它们出现了,现在它们(至少暂时(消失了。自动内存管理(GC是其中的清理部分(是一个概率函数,而不是确定性函数,因为堆中的对象位置可能会根据随机变化而变化,例如对象的分配顺序略有不同。如果我在操作系统,如果没有看到GC日志显示一切正常,我不会相信改进。
另一种可能性是,如果缓存大小随着时间的推移波动很大,使得堆填充变化很大,那么使用小的-Xms设置,堆可能会增长和收缩更多。当堆收缩时,执行压缩以将分布在大堆空间中的活动对象移动到新的较小空间中,从而使小堆处于连续的内存地址范围内。堆收缩压缩通常发生在系统不是很忙的时候(这就是堆非常空的原因(,并且需要处理的实时数据较少,因此压缩时间更短,不太可能显著影响性能。
通常,最好的GC性能将通过将-Xms和-Xmx设置为相同来实现,因为这样根本不会发生堆大小调整。然而,要知道合适的大小是多少,您应该启用GC日志记录,并检查覆盖一周或更长时间操作的日志。堆的大小应确保在全局GC之后至少有30%的使用期空间是可用的,这样执行GC所花费的时间就不会过多。