Вопрос-ответ

Does GC release back memory to OS?

Освобождает ли GC память обратно в ОС?

Когда сборщик мусора запускается и освобождает память, возвращается ли эта память обратно в ОС или она сохраняется как часть процесса. У меня сложилось сильное впечатление, что память на самом деле никогда не освобождается обратно в ОС, а сохраняется как часть области памяти / пула для повторного использования тем же процессом.

В результате фактическая память процесса никогда не уменьшится. Статья, которая напомнила мне, была такой, и среда выполнения Java написана на C / C ++, так что, я полагаю, применимо то же самое?

Обновить
Мой вопрос о Java. Я упоминаю C / C ++, поскольку предполагаю, что выделение / освобождение Java выполняется JRE с использованием некоторой формы malloc / delete

Переведено автоматически
Ответ 1

HotSpot JVM действительно освобождает память обратно в ОС, но делает это неохотно, поскольку изменение размера кучи обходится дорого, и предполагается, что если вам понадобилась эта куча однажды, она понадобится вам снова.

В целом способность к сжатию и поведение зависят от выбранного сборщика мусора, версии JVM, поскольку возможность сжатия часто появлялась в более поздних версиях задолго до добавления самого GC. Некоторым сборщикам также может потребоваться передача дополнительных параметров для выбора режима сжатия. А некоторые, скорее всего, никогда не будут это поддерживать, например, EpsilonGC. Итак, если требуется сокращение кучи, его следует протестировать для конкретной версии JVM и конфигурации GC.

JDK 8 и более ранние версии

В этих версиях нет явных опций для быстрого восстановления памяти, но вы можете сделать GC более агрессивным в целом, установив -XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30, который позволит ему тратить больше процессорного времени на сбор и ограничить объем выделенной, но неиспользуемой памяти кучи после цикла GC.

Если вы используете параллельный сборщик, вы также можете установить -XX:InitiatingHeapOccupancyPercent=N с N на некоторое низкое значение, чтобы позволить GC запускать параллельные коллекции почти непрерывно, что потребляет еще больше циклов процессора, но быстрее сокращает кучу. Это обычно не очень хорошая идея, но на некоторых типах машин с большим количеством свободных ядер ЦП, но с нехваткой памяти это может иметь смысл.

Если вы используете G1GC, обратите внимание, что он получил возможность возвращать неиспользуемые фрагменты в середине кучи с jdk8u20, более ранние версии могли возвращать фрагменты только в конце кучи, что накладывало значительные ограничения на то, какой объем может быть восстановлен.

Если вы используете сборщик с заданным по умолчанию временем паузы (например, CMS или G1), вы также можете ослабить эту цель, чтобы налагать меньше ограничений на сборщик, или вы можете переключиться на параллельный сборщик, чтобы уделять приоритетное внимание времени паузы.

Чтобы проверить, происходит ли сжатие, или диагностировать, почему GC решает не сокращать, вы можете использовать ведение журнала GC с помощью -XX:+PrintAdaptiveSizePolicy также может дать представление, например, когда JVM пытается использовать больше памяти для молодого поколения для достижения некоторых целей.

JDK 9

Добавлен -XX:-ShrinkHeapInSteps параметр, который можно использовать для более агрессивного применения сжатия, вызванного параметрами, упомянутыми в предыдущем разделе. Соответствующая ошибка OpenJDK.

Для ведения журнала -XX:+PrintAdaptiveSizePolicy заменено на -Xlog:gc+ergo

JDK 12

Добавлена возможность включить быстрое освобождение памяти для G1GC через G1PeriodicGCInterval (JEP 346), опять же за счет некоторого дополнительного процессора. В JEP также упоминаются аналогичные функции в Шенандоа и виртуальной машине OpenJ9.

JDK 13

Добавляет аналогичное поведение для ZGC, в данном случае оно включено по умолчанию. Дополнительно XXSoftMaxHeapSize может быть полезно для некоторых рабочих нагрузок поддерживать средний размер кучи ниже некоторого порогового значения, сохраняя при этом временные всплески.

Ответ 2

JVM действительно освобождает память обратно при некоторых обстоятельствах, но (по соображениям производительности) этого не происходит всякий раз, когда часть памяти собирается мусором. Это также зависит от JVM, ОС, сборщика мусора и т.д. Вы можете отслеживать потребление памяти вашим приложением с помощью JConsole, VisualVM или другого профилировщика.

Также смотрите этот связанный отчет об ошибке

Ответ 3

Если вы используете сборщик G1 и время от времени вызываете System.gc() (я делаю это раз в минуту), Java надежно сократит кучу и вернет память ОС.

Начиная с Java 12, G1 делает это автоматически, если приложение простаивает.

Я рекомендую использовать эти параметры в сочетании с приведенным выше предложением для обеспечения очень компактного размера резидентного процесса:

-XX:+UseG1GC -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10

Я использую эти опции ежедневно в течение нескольких месяцев с большим приложением (целой гостевой ОС на базе Java) с динамически загружаемыми и выгружаемыми классами - и объем Java-процесса почти всегда составляет от 400 до 800 МБ.

Ответ 4

Эта статья здесь объясняет, как работает GC в Java 7. В двух словах, доступно множество различных сборщиков мусора. Обычно память хранится для процесса Java, и только некоторые GCS освобождают ее системе (я думаю, по запросу). Но объем памяти, используемый процессом Java, не будет расти бесконечно, поскольку существует верхний предел, определенный параметром Xmx (обычно это 256 мб, но я думаю, что это зависит от ОС / компьютера).

java