Эта статья объясняет концепцию грязных карт и их роль в молодом GC.
В обоих случаях один адрес памяти в старом пространстве «загрязнен» и, таким образом, представляет собой одну карту. Для объекта эталонного массива, охватывающего несколько карт (блоки по 512 байт), модифицируется только карта для действительно измененного поддиапазона индекса.
Так как только одна карта «перезагружена», GC необходимо сканировать только 512 байтов памяти.
С -XX:+UseConcMarkSweepGC
обе версии "smallArr" и "bigArr" показывают одинаковое время.
-XX:+UseConcMarkSweepGC
+ smallArr
[GC (Allocation Failure) [ParNew: 419458K->2K(471872K), 0.0015320 secs] 485365K->65909K(996160K), 0.0015635 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
-XX:+UseConcMarkSweepGC
+ bigArr
[GC (Allocation Failure) [ParNew: 419458K->2K(471872K), 0.0020550 secs] 485365K->65909K(996160K), 0.0020885 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
Хотя это -XX:+UseParallelOldGC
, похоже, что GC должен сканировать весь "bigArr"
-XX:+ParallelOldGC
+ smallArr
[GC (Allocation Failure) [PSYoungGen: 522768K->16K(523520K)] 588691K->65939K(1047808K), 0.0009430 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
-XX:+ParallelOldGC
+ bigArr
[GC (Allocation Failure) [PSYoungGen: 522768K->16K(523008K)] 588687K->65935K(1047296K), 0.0149276 secs]
[Times: user=0.03 sys=0.00, real=0.02 secs]
-XX:+ParallelOldGC
+ bigArr = new Object[1 << 25]
[GC (Allocation Failure) [PSYoungGen: 522768K->16K(523520K)] 654219K->131467K(1047808K), 0.0413473 secs]
[Times: user=0.09 sys=0.00, real=0.04 secs]
Счетчик интуитивно ParallelOldGC
и ConcMarkSweepGC
используют различные реализации очень похожего алгоритма молодого GC.
Похоже, в PSYoungGen
отсутствует оптимизация для сканирования только грязной части массива объектов.