手动 GC 调用的用例?

Posted

技术标签:

【中文标题】手动 GC 调用的用例?【英文标题】:A use case for a manual GC invocation? 【发布时间】:2016-08-26 01:10:21 【问题描述】:

我读过why is it bad practice to call System.gc(),还有很多其他的,例如this one 描述了对 System.gc() 的真正灾难性滥用。但是,在某些情况下,GC takes too long 和避免长时间的停顿(例如,avoiding garbage)并不是很简单,并且会使代码更难维护。

恕我直言,在以下常见情况下手动调用 GC 是可以的:

有多个可互换的网络服务器,它们前面有故障转移。 每台服务器都使用几 GB 的堆,STW 暂停所用的时间比平均请求长得多。 故障转移不知道 GC 何时发生。 故障转移可以在被告知时免除服务器。

算法看起来很简单:周期性地选择一个服务器,让它不再有请求发送给它,让它完成它正在运行的请求,让它做它的 GC,然后重新激活服务器。

我想知道我是否遗漏了什么?1,2

有什么选择?

    长时间运行的请求可能是个问题,但我们假设没有。或者只是将等待时间限制在与 GC 所需时间相当的一段时间。让一个缓慢的请求变得更慢听起来还不错。

    -XX:+DisableExplicitGC 之类的选项可能会使算法无用,但不要使用它(我的用例包括我负责的专用服务器)。

【问题讨论】:

imo 如果没有损坏,请不要修复它。如果您没有看到内存导致的性能瓶颈,那何必担心呢? @MitchWeaver 同意,只有在您确定自动 GC 无法执行您想要的操作时,您才应该尝试控制它。 @MitchWeaver 我称之为刨。许多项目都遇到了 GC 问题,所以我也应该期待它们。知道有一个好的解决方案让我现在不用担心。我的问题的原因是每个人都声称“天堂禁止呼叫 GC!”之类的东西,所以我正在寻找确认。 【参考方案1】:

对于低延迟交易系统,我以非典型方式使用 GC。

您希望避免任何收款,即使是交易日的小额收款。一种方法是每秒创建少于 300 KB 的垃圾。这大约是每小时 1 GB,或每天最多 24 GB。当您使用 24 GB 的 Eden 空间时,这意味着没有次要/主要 GC。但是,为了确保 GC 在计划和可接受的时间发生,每天早上 5 点会调用System.gc(),这样您第二天就有一个干净的 Eden 空间。

有时,您创建的垃圾比预期的要多,例如无法重新连接到数据源,您可能会获得少量次要集合。然而,这只发生在出现问题时。

更多详情http://vanillajava.blogspot.co.uk/2011/06/how-to-avoid-garbage-collection.html

避免垃圾并不是一件小事,而且会使代码更难维护。

完全避免垃圾几乎是不可能的。但是 300 KB/s 对于 JVM 来说并不难。 (如今,您可以在一台具有 24 GB Eden 空间的机器上拥有多个 JVM)

请注意,如果您可以将垃圾保持在 50 KB/s 以下,您可以在没有 GC 的情况下运行一周。

定期选择一个服务器,不再向它发送任何请求,让它完成它的运行请求,让它做它的GC,然后重新激活服务器。

您可以将 GC 视为未能满足您的 SLA 条件。在这种情况下,当您确定这将要从集群中发生时,您可以删除服务器,将其完全 GC 并将其返回到集群。

【讨论】:

【参考方案2】:

但是,有些情况下 GC 花费的时间过长并避免了长时间的停顿

你必须区分由young-only、混合/并发阶段和full GC引起的暂停。

在大多数情况下,您希望避免完整的 GC,而其他的可以接受,这通常可以通过一些 GC 调整和优化代码来避免大的分配突发。

原则上,G1 应该能够在年轻/混合循环上永远运行,并且可以将完整 GC 视为软故障。通过仔细调整,CMS 至少可以持续很多天,但最终可能会屈服于碎片并需要完整的 GC 来进行压缩。

如果即使年轻 GC 暂停也不可接受,或者垃圾堆积得太快,并发阶段无法以可接受的暂停时间处理,那么您概述的策略可能是一种可行的解决方法。

请注意,还有其他手动触发 GC 的用例,例如 GC 管理的本机资源,例如直接字节缓冲区,虽然这些通常相当麻烦。

另请注意,并非所有System.gc() 调用都是平等的,还有ExplicitGCInvokesConcurrent 选项。

【讨论】:

以上是关于手动 GC 调用的用例?的主要内容,如果未能解决你的问题,请参考以下文章

FutureProvider 的用例

Python + Appium 已解决driver(session)在多个class之间复用,执行完一个类的用例,再次执行下个类的用例时不需要初始化

持久的有序消息代理的用例是啥

pytest-14-函数传参和firture传参数request

httprunner 2.x学习16 - 调用HttpRunner类执行用例

pytest文档14-函数传参和firture传参数request