手动GC调用的用例?

时间:2016-05-01 03:07:22

标签: java performance garbage-collection failover

我已阅读why is it bad practice to call System.gc()以及其他许多内容,例如this one描述了对System.gc()的真正灾难性滥用。但是,有些情况下,GC takes too long并避免长时间暂停(例如avoiding garbage)并非完全无关紧要,并且会使代码难以维护。

在以下常见情况下,IMHO手动调用GC很好:

  • 有多个可互换的网站,并在其前面进行故障转移。
  • 每个服务器使用几千兆字节的堆,而STW暂停所需的时间比一般的请求要长得多。
  • 故障转移时不知道GC何时会发生。
  • 故障转移可以在被告知时免除服务器。

算法似乎微不足道:定期选择服务器,不再向其发送请求,让它完成运行请求,让它执行GC,然后重新激活服务器。

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

有哪些替代方案?

  1. 长时间运行的请求可能是一个问题,但我们假设没有。或者只是限制等待一段时间与GC相当的时间。慢速请求甚至更慢也不会太糟糕。

  2. -XX:+DisableExplicitGC这样的选项可能会使算法失效,但只是不使用它(我的用例包括我负责的专用服务器)。

2 个答案:

答案 0 :(得分:2)

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

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

有些时候,当您创造的垃圾超出预期时,例如无法重新连接到数据源,您可能会获得少量的次要集合。然而,只有在出现问题时才会发生这种情况。

有关详细信息http://vanillajava.blogspot.co.uk/2011/06/how-to-avoid-garbage-collection.html

  

通过避免垃圾并不是一件容易的事情,并且使代码难以维护。

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

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

  

定期选择服务器,不再向其发送请求,让它完成运行请求,让它执行GC,然后重新激活服务器。

您可以将GC视为无法满足您的SLA条件。在这种情况下,您可以在确定将要从群集中执行此操作时删除服务器,完整GC并将其返回到群集。

答案 1 :(得分:2)

  

但是,有些情况下GC需要太长时间并且避免长时间暂停

你必须区分由年轻人,混合/并发阶段和完整的GC引起的暂停。

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

原则上G1应该能够在年轻/混合循环中永久运行,并且完整的GC可以被认为是软故障。 CMS可以通过仔细调整至少这样做很多天,但最终可能会死于碎片,需要一个完整的GC进行压缩。

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

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

另请注意,并非所有System.gc()个调用都是相同的,也有ExplicitGCInvokesConcurrent个选项。