为什么等待太久从年轻一代提升一个对象会导致效率低下?
Why does waiting too long to promote an object from the young generation result in less efficiency?
为什么从年轻代提升对象的时间过长导致效率低下?
我看到的一个解释说,如果你等待太久来提升年轻代,它会变得不那么稀疏(即 live set 的大小会变大,以占年轻代总大小的百分比来看) .
但这怎么会导致效率降低呢?假设当年轻一代稀疏时(比如,live set 是其大小的 2%),收集它需要 X
CPU 时间,并且在一段时间内 T
收集 50 次将花费 50X
CPU 时间。相反,如果我们等到它填满其大小的 100%(这也需要一段时间 T
发生),一次收集所有的时间应该只需要相应的时间,即 (100/2)*X=50X
CPU 时间。所以最终,收集所花费的总时间将是相同的——无论您是在 2% 的占用率下收集 50 次,还是在 100% 的占用率下收集一次。第一种方法的效率优势在哪里?
正在复制。
年轻一代中的大多数对象都死了,根本不会被 GC 触及(是的,它实际上是一个 幸存者收集器,存活的对象被复制,剩下的是可用内存)。
在几个小集合中幸存下来的对象可能会长寿。所以一遍又一遍地复制它会浪费时间。
if instead we wait until it has filled up to 100% of its size
您没有这个选项。每当伊甸园 space 变得(几乎)满时,你就会收集。如果只使用了 2%,你什么都不做。但是...
收集完成后,您会发现可能只有 2% 的对象存活下来。
你的错误是误解了百分比。这 2% 不是门槛,它是结果,你没有办法改变它。您可以更改伊甸园大小等,但对幸存者百分比的影响只是间接的。
一个原因是,新一代中的每个对象将从eden复制到survivor 然后在 幸存者空间 之间多次。因此,如果您知道一个实例不会早逝,那么快速提升它会减少副本的数量。如果对象在老年代,它通常不会被复制(只被遍历)。这不仅减少了复制操作的次数,还减少了在所有引用中更改实例地址的需要。
年轻代复制收集器没有碎片问题,所以不是这个原因。
然而,应该提到的是,知道一个对象是否早逝并非易事。如果您的 运行 事务非常短,您可以假设大多数对象很快就会死亡,因此(根本)没有必要将它们保存在幸存者空间中。
为什么从年轻代提升对象的时间过长导致效率低下?
我看到的一个解释说,如果你等待太久来提升年轻代,它会变得不那么稀疏(即 live set 的大小会变大,以占年轻代总大小的百分比来看) .
但这怎么会导致效率降低呢?假设当年轻一代稀疏时(比如,live set 是其大小的 2%),收集它需要 X
CPU 时间,并且在一段时间内 T
收集 50 次将花费 50X
CPU 时间。相反,如果我们等到它填满其大小的 100%(这也需要一段时间 T
发生),一次收集所有的时间应该只需要相应的时间,即 (100/2)*X=50X
CPU 时间。所以最终,收集所花费的总时间将是相同的——无论您是在 2% 的占用率下收集 50 次,还是在 100% 的占用率下收集一次。第一种方法的效率优势在哪里?
正在复制。
年轻一代中的大多数对象都死了,根本不会被 GC 触及(是的,它实际上是一个 幸存者收集器,存活的对象被复制,剩下的是可用内存)。
在几个小集合中幸存下来的对象可能会长寿。所以一遍又一遍地复制它会浪费时间。
if instead we wait until it has filled up to 100% of its size
您没有这个选项。每当伊甸园 space 变得(几乎)满时,你就会收集。如果只使用了 2%,你什么都不做。但是...
收集完成后,您会发现可能只有 2% 的对象存活下来。
你的错误是误解了百分比。这 2% 不是门槛,它是结果,你没有办法改变它。您可以更改伊甸园大小等,但对幸存者百分比的影响只是间接的。
一个原因是,新一代中的每个对象将从eden复制到survivor 然后在 幸存者空间 之间多次。因此,如果您知道一个实例不会早逝,那么快速提升它会减少副本的数量。如果对象在老年代,它通常不会被复制(只被遍历)。这不仅减少了复制操作的次数,还减少了在所有引用中更改实例地址的需要。
年轻代复制收集器没有碎片问题,所以不是这个原因。
然而,应该提到的是,知道一个对象是否早逝并非易事。如果您的 运行 事务非常短,您可以假设大多数对象很快就会死亡,因此(根本)没有必要将它们保存在幸存者空间中。