Похоже, вы не дали достаточно кучу JVM. Конечно, рабочий набор может умещаться в 1 Гбайт, но вам все равно нужно дать больше. Чтобы понять почему, читайте дальше.
Предположим, что когда работает сборщик мусора, он выполняет объем работы W1
, который пропорционален количеству не мусора, который он сканирует для идентификации мусора, и другого объема работы W2
, который пропорционально количеству мусора, который он находит. (На самом деле, это немного сложнее, чем это ... но давайте сделаем анализ простым.)
Предположим, что у вас есть куча 1Гб кучи с 0,9Гб, занятой достижимыми объектами. Каждый раз, когда GC запускается, он может освободить не более 0,1 Гб пространства кучи, и при этом ему необходимо выполнить W1 * 0.9Gb + W2 * 0.1Gb
работы. Объем работы на один восстановленный байт составляет (W1 * 0.9Gb + W2 * 0.1Gb) / 0.1Gb
; то есть 9 * W1 + W2
.
Теперь предположим, что у вас есть куча 2 ГБ с 0,9 ГБ, занятые достижимыми объектами. Теперь объем работы на один восстановленный байт равен (W1 * 0.9Gb + W2 * 1.1Gb) / 1.1Gb
или W1 * 9/11 + W2
.
Если вы сравните эти два значения, вы увидите, что сборщик мусора выполняет примерно на W1 * 8
больше работы на байт, возвращаемой в куче 1 Гб, по сравнению с кучей 2 Гб.
Как правило, чем ближе к полной вы запускаете кучу, тем более неэффективным будет сборщик мусора. Уроки:
настроить JVM для использования щедрой кучи и
настроить JVM на выдачу OOM, если после выполнения полного GC осталось менее 25% свободного места в куче.