Есть ли способ снизить кучу Java, когда он не используется? - PullRequest
51 голосов
/ 10 февраля 2011

Сейчас я работаю над Java-приложением и оптимизирую его использование памяти.Насколько я знаю, я следую рекомендациям по правильному сбору мусора.Тем не менее, похоже, что моя куча, кажется, сидит в своем максимальном размере, даже если он не нужен.

Моя программа запускает ресурсоемкую задачу один раз в час, когда компьютер не используется человеком.Эта задача использует приличный кусок памяти, но затем освобождает все это сразу после завершения задачи.Профилировщик NetBeans показывает, что использование памяти выглядит следующим образом:

Java program memory usage

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

Возможно ли это?Благодаря.

Ответы [ 7 ]

34 голосов
/ 10 февраля 2011

Возможно, вы можете поиграть с -XX:MaxHeapFreeRatio - это максимальный процент (по умолчанию 70) кучи, которая свободна до того, как GC сжимает ее.Возможно, установив его немного ниже (40 или 50?), А затем с помощью System.gc() может пойти на некоторые шаги, чтобы получить желаемое поведение?

Однако нет способа заставить это произойти, вы можете попробоватьJVM, чтобы сделать это, но вы не можете просто вырвать память, как и когда вы хотите.И хотя вышеперечисленное может уменьшить объем кучи, эта память не обязательно будет возвращена обратно в ОС (хотя в недавних реализациях JVM это происходит).

13 голосов
/ 08 июля 2015

Короткая версия: Да, вы можете.

Длинная версия:

Как Java / JVM управляет памятью

Для большинства приложений JVM по умолчанию в порядке.Похоже, что JVM ожидает, что приложения будут работать только в течение ограниченного периода времени.Следовательно, он не освобождает память самостоятельно.

Чтобы помочь JVM решить, как и когда выполнять сборку мусора, необходимо указать следующие параметры:

  • -Xms Указывает минимальный размер кучи
  • –Xmx Указывает максимальный размер кучи

Для серверных приложений добавьте: -server

Этого мне недостаточно,Я хочу больше контроля!

Если вышеупомянутых параметров недостаточно, вы можете повлиять на поведение JVM в отношении сборки мусора.

Сначала вы можете использовать System.gc(), чтобы сообщить виртуальной машинекогда вы считаете, что сбор мусора имеет смысл.Во-вторых, вы можете указать, какой из сборщиков мусора должна использовать JVM:

Различные виды сборщиков мусора:

  • Serial GC

    Параметр командной строки: -XX:+UseSerialGC

    Останавливает ваше приложение и выполняет GC.

  • Параллельный GC

    КомандаСтроковый параметр: -XX:+UseParallelGC -XX:ParallelGCThreads=value

    Запускает вспомогательные коллекции параллельно с вашим приложением.Сокращает время, необходимое для основных коллекций , но использует другой поток.

  • Параллельное сжатие GC

    Параметр командной строки: -XX:+UseParallelOldGC

    Запускает основных коллекций параллельно с вашим приложением.Использует больше ресурсов ЦП, уменьшает использование памяти.

  • CMS GC

    Параметр командной строки: -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=value -XX:+UseCMSInitiatingOccupancyOnly

    Выполняет меньшеколлекции, и чаще, чем Serial GC , что ограничивает перерывы / остановки приложения.

  • G1

    Параметр командной строки: -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

    Экспериментальный (по крайней мере, в Java 1.6): Пытается убедиться, что приложение никогда не останавливается в течение более 1 с.

    Пример

Использование памяти веб-приложением Play Framework без каких-либо оптимизаций: Play Framework WebApp without optimizations Как видите, оно использует довольно много места в куче, и используемое пространство регулярно освобождается.

В этом случае оптимизации только с параметрами были неэффективными.Было несколько запланированных заданий, которые занимали довольно много памяти.В этом случае наилучшая производительность была достигнута при использовании CMS GC в сочетании с System.gc() после операций с интенсивным использованием памяти.В результате использование памяти WebApp было уменьшено с 1,8 ГБ до 400-500 МБ.

Здесь вы можете увидеть еще один скриншот из VisualVM, который показывает, как память освобождается JVM и фактически возвращается кОС:

Memory is being freed by the JVM and returned to the OS Примечание. Я использовал кнопку «Perform GC» VisualVM для выполнения GC, а не System.gc() в моем коде, как запланированные задачи, которые потребляютпамять запускается только в определенное время, и ее несколько сложнее захватить с помощью VisualVM.

Дальнейшее чтение

4 голосов
/ 10 февраля 2011

JVM не работает таким образом. Вы не можете вернуть его ОС.

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

3 голосов
/ 28 июля 2011

Java лучше хранить в секрете: -Xincgc Это влияет на производительность, но не всегда так сильно. Иногда это зависит от того, что вы делаете. Инкрементный сборщик мусора хорошо возвращает память системе!

3 голосов
/ 10 февраля 2011

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

http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/

3 голосов
/ 10 февраля 2011

Одна из возможностей - заставить ваше фоновое java-приложение запускать внешний экземпляр jvm каждый час для запуска вашей задачи. Таким образом, между вашими задачами будет работать только ваше оригинальное приложение jvm.

2 голосов
/ 21 января 2019

Java 12 поддерживает эту функцию с помощью G1GC.

JEP 346: быстро возвращать неиспользуемую зарезервированную память из G1.

Автоматическое улучшение сборщика мусора G1возвращать кучи памяти Java операционной системе в режиме ожидания.

https://openjdk.java.net/jeps/346

Java 13 поддерживает эту функцию, используя zgc

JEP 351: ZGC: Uncommit Unused Memory

ZGC в настоящее время не отменяет передачу и возвращает память операционной системе, даже если эта память не использовалась в течение длительного времени.Такое поведение не является оптимальным для всех типов приложений и сред, особенно для тех, где объем памяти является проблемой.Например: Контейнерные среды, в которых ресурсы оплачиваются путем использования.

  • Среды, в которых приложение может простаивать в течение длительных периодов времени и совместно использовать или конкурировать за ресурсы со многими другими приложениями.

  • Приложение может иметь очень разные требования к пространству кучи во время его выполнения.Например, куча, необходимая во время запуска, может быть больше, чем требуется позже во время выполнения в устойчивом состоянии.

http://openjdk.java.net/jeps/351

...