至少在旧的GCs中,这是正确的。(我知道有一些像ZGC和Shenandoah这样的新公司致力于消除这种情况)
据我所知,GC保存有生命对象的轨迹,那么GC时间不应该主要受对象数量(活动/需要清除)的影响吗?
编辑:i的意思是在容量方面增长,意味着堆更大,但应用程序对它的利用率是相同的。
发布于 2020-02-29 11:26:31
你没回答自己的问题吗?
据我所知,
保存有活动对象的跟踪,所以GC时间不应该主要受对象数量(活动/需要清除)的影响吗?
堆增长得越多,拥有的活动对象越多,GC就越慢(我肯定这条规则有例外,特别是对于小集合,但这是一个粗略的想法)。要清除的对象数量是不相关的,最重要的是活动对象的总数。现在,如果您的堆正在增长,因为您正在存储长期存在的对象,那么只要您不继续添加更多的对象,它可能是可以的。最终,长寿的物体将向幸存者空间移动,并且只会受到大型收藏的影响,而不会受到次要的影响。只要小GC始终能从年轻一代中获得足够的内存,就不会在所有对象(包括长寿对象)上触发主GC。
我还观察到了G1的不同行为。我们有一个低延迟的应用程序(40 5ms p99),所以我们尝试配置G1来进行非常短的暂停(不记得有多少,也许5ms左右)。发生的情况是,G1或多或少地达到了5ms的目标,但它必须非常频繁地运行,因为5ms不足以处理堆中的所有死对象。因此,不完全正确地说,随着堆大小的增加,单个垃圾收集的运行速度会变慢,但是,在给定的一段时间内,垃圾收集的平均时间很可能会增加。
发布于 2020-03-03 22:38:51
有许多不同的算法可以用来实现垃圾收集。并不是所有的人都表现出你提到的行为。
在你的问题中,你指的是使用标记扫描形式的算法。如果我们以HostSpot JVM为例,可以使用CMS收集器收集旧一代。这使用了标记阶段,其中所有可从应用程序代码访问的对象都被标记。最初,一组直接可访问的对象(堆栈上的对象引用、寄存器等)。被创造出来了。该集合中的每个对象都在其标头中设置了标记位,以指示其仍在使用中。来自这些对象的所有引用都是递归的,并且每个可访问的对象都有标记位集。这需要多长时间与活动对象的数量成正比,而不是堆的大小。
然后,扫描阶段必须扫描整个堆,寻找具有标记位集的对象,并确定它们之间的间隙,以便将它们添加到空闲列表中。这些被用来为年轻一代所推广的对象分配空间。因为必须对整个堆进行扫描,因此所花费的时间与堆的大小成正比,而不管堆中有多少活数据。
在G1的情况下,算法是相似的,但是每一代堆被划分成区域,这样就可以更有效地回收空间。
https://stackoverflow.com/questions/60464538
复制相似问题