首页 > 解决方案 > 缩小 -Xms 改进了 GC 时间

问题描述

我们有一个 AIX-Websphere java7 服务器,它使用一个非常大的内存表/数组对象,通常大小约为 3.1 GB。对于此服务器,我们配置了 -Xms=3072m 和 -Xmx=3840m(GC 算法=gencon)。根据 Dynatrace 的说法,它工作正常,直到有一天突然将 GC 时间从毫秒增加到每分钟秒。

巨大的对象通常会增长,因为几乎没有删除,没有更新,而是不断的插入流。

尝试不同的方法,我们改进了 GC 时间(同样以毫秒为单位),只需将 -Xms 更改为 1024m。

有谁知道什么原理允许这种改进只是缩小 Xms 的大小?我在其他帖子中读到的是相反的。也就是说,增加 Xms 甚至将其与 Xmx 匹配将是最佳方法。

标签: javamemorygarbage-collectionwebsphereheap-memory

解决方案


长时间的 GC 暂停可能是由于堆碎片需要压缩以将某些对象放置在堆的使用期限区域中。如果最大 3840m 堆中的 3.1 GB 被缓存对象占用,那么在 Java 程序执行时发生的正常对象分配和删除流程在堆中的工作空间非常小。由于 Java 对象必须分配在连续的内存空间中,如果分配的某个对象在堆内存中没有足够大的连续空间可用,则需要进行压缩。压缩是一个相对较长的缓慢过程,它重新排列堆中对象的位置,以消除对象之间的小空间并为新分配创建一个大的连续区域(如对旧 Windows 系统上的硬盘驱动器进行碎片整理)。

坦率地说,我很惊讶您描述的配置会表现良好。除了提到的“缓存对象”(可能这实际上是许多小对象的集合?)之外,还有一个实现 WebSphere 运行时的长期对象的基线集,通常需要超过 100 MB。然后在任何 Java 系统中,都有一个不断创建和删除对象的流程(通过垃圾收集)。一个典型的经验法则是调整堆的大小,以便在全局 GC 之后,任期区域有 50% 的空闲空间 - 在全局 GC 之后任何少于 20% 的空闲空间都会导致不希望的 GC 开销。

您是否在此配置中启用了详细的 GC 日志记录?这是真正了解堆内部发生了什么的唯一方法,并且知道这对 Java 系统的健康和性能至关重要。我们建议在所有 Java 系统、生产环境和测试环境中启用 GC 日志记录(通过将 -verbose:gc 添加到 JVM 参数)。IBM Java 中 GC 日志的开销非常低,诊断价值非常高。

至于为什么设置 -Xms1024 会提高性能有几种可能。

首先,此更改可能实际上并没有解决任何问题。您有一段时间没有看到长时间的 GC 暂停,然后它们出现了,现在它们(至少暂时)消失了。自动内存管理(其中 GC 是清理部分)是一种概率函数,而不是确定性函数,因为堆中的对象放置可以根据随机变化而改变,例如对象分配的顺序略有不同。如果我正在操作系统,如果没有看到显示一切正常的 GC 日志,我不会相信改进。

另一种可能性是,如果缓存大小随时间波动很大,导致堆填充变化很大,那么使用小的 -Xms 设置,堆可能会增长和缩小更多。当堆收缩时,执行压缩以将分布在大堆空间中的活动对象移动到新的较小空间中,这样小堆将处于连续的内存地址范围内。堆收缩压缩通常会在系统不是很忙(这就是堆非常空)并且要处理的实时数据较少时发生,因此压缩将更短并且不太可能显着影响性能。

一般来说,最好的 GC 性能将通过将 -Xms 和 -Xmx 设置为相同来实现,因为这样根本不会发生堆大小调整。但是,要知道合适的大小是多少,您应该启用 GC 日志记录并检查涵盖一周或更长时间操作的日志。应该调整堆的大小,以便在全局 GC 之后至少有 30% 的任期空间是空闲的,这样执行 GC 所花费的时间不会过多。


推荐阅读