这是另一个“请告诉我如何强制 Java 垃圾收集器运行”的问题。在我们的应用程序中,我相信我们有充分的理由这样做。
这是一个服务器应用程序,通常有大约 500 万个活动对象。每 5 分钟一次,我们执行一个大约需要 60 秒的分析任务。如果在分析运行时触发了完整的 GC,则将有大约 40M 的活动对象。分析完成后,额外的 35M 对象变为垃圾。服务器必须始终保持对请求的响应(即使在分析运行时)。
我们发现,如果在分析未运行时调用完整的 GC 大约需要 1.5 秒,但在分析运行时大约需要 15 秒。不幸的是,我们的分配模式使得完整的 GC 通常在分析期间触发,即使分析只运行了 20% 的时间。(每第三或第四次分析运行触发一次完整的 GC。)
如果老一代中的可用空间低于某个阈值(5GB),我在开始分析运行之前添加了代码来调用备受鄙视的 System.gc()。好处是非常可观的:我们获得了 1.5 秒的暂停时间而不是 15 秒的暂停时间,并且我们将更多的垃圾释放到交易中。但是,有时 System.gc() 调用会被忽略,几分钟后我们会在自动触发 GC 时暂停 15 秒。
那么我的问题是:我们可以做些什么来更有力地说服垃圾收集器运行吗?我们正在运行 1.7.0_09-icedtea 并使用 Parallel GC。我想要(a)一种手动强制垃圾收集的可靠方法,或者(b)某种方式来调整收集器,以便它做出更智能的自动决策。(b) 似乎很难,因为我不清楚收集器如何检测到我们的工作集以这种戏剧性的方式变化。
如果需要,我愿意求助于大量黑客;这对我们来说是一个严重的问题。(我们可能会考虑使用 CMS 或 G1 压缩器作为替代方案,但我对 CMS 对吞吐量的影响持怀疑态度,而且 G1 被认为在我们使用的大字节数组中表现不佳。)
附录:在生产中,到目前为止,我们的经验是 System.gc()通常确实会触发完整的垃圾回收;至少,在我们调用它的情况下。(我们只每 10 到 30 分钟调用一次,堆中有些但没有完全填满垃圾。)能够更可靠地触发垃圾收集会很好,但它在大多数情况下都对我们有帮助。