Подтвердить что ты не робот

Есть ли способ снизить кучу Java, когда он не используется?

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

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

Java program memory usage

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

Возможно ли это? Спасибо.

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

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

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

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

Мне этого мало. Я хочу больше контроля!

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

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

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

  • Последовательный 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 без оптимизации Как вы можете видеть, в нем используется довольно много кучи, и используемое пространство регулярно освобождается.

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

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

Память освобождается JVM и возвращается в ОС Примечание: я использовал кнопку "Выполнить GC" VisualVM для выполнения GC, а не System.gc() в моем коде, поскольку запланированные задачи, которые потребляют память, запускаются только в определенное время и несколько сложнее захватить с помощью VisualVM.

Дополнительная литература

Ответ 3

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

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

Ответ 4

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

Ответ 6

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

Ответ 7

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

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

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

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

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

JEP 351: ZGC: неиспользуемая неиспользуемая память

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

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