Есть ли способ снизить кучу Java, когда он не используется?
В настоящий момент я работаю над Java-приложением и оптимизирую его использование памяти. Насколько я знаю, я слежу за рекомендациями по сборке мусора. Однако кажется, что моя куча, кажется, сидит в максимальном размере, хотя она не нужна.
Моя программа запускает ресурсоемкую задачу один раз в час, когда компьютер не используется человеком. Эта задача использует приличный кусок памяти, но затем освобождает все сразу после завершения задачи. Профилировщик NetBeans показывает, что использование памяти выглядит следующим образом:
![Java program memory usage]()
Я бы очень хотел вернуть все это кучу обратно в ОС, когда он не используется. У меня нет оснований бояться всего этого, пока программа даже не будет делать что-либо хотя бы на час.
Возможно ли это? Спасибо.
Ответы
Ответ 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 без каких-либо оптимизаций:
Как вы можете видеть, в нем используется довольно много кучи, и используемое пространство регулярно освобождается.
В этом случае оптимизация только с параметрами не была эффективной. Были некоторые запланированные задачи, которые использовали довольно много памяти. В этом случае наилучшая производительность была достигнута с помощью CMS GC
в сочетании с System.gc()
после интенсивных операций с памятью. В результате использование памяти WebApp памяти было снижено с 1,8 ГБ до 400-500 МБ.
Здесь вы можете увидеть еще один снимок экрана из VisualVM, который показывает, как память освобождается JVM и фактически возвращается в ОС:
Примечание: я использовал кнопку "Выполнить GC" VisualVM для выполнения GC, а не System.gc()
в моем коде, поскольку запланированные задачи, которые потребляют память, запускаются только в определенное время и несколько сложнее захватить с помощью VisualVM.
Дополнительная литература
Ответ 3
JVM не работает. Вы не можете вернуть его ОС.
Как отмечалось несколькими людьми, так как это было написано четыре года назад, вы можете вернуть память в ОС, если вы предоставите правильные настройки GC для JVM.
Ответ 4
Одна из возможностей заключается в том, чтобы ваше фоновое java-приложение запускало внешний экземпляр jvm каждый час для запуска вашей задачи. Таким образом, только одно исходное приложение jvm работает между задачами.
Ответ 5
Если ваше приложение находится в состоянии покоя в периоды бездействия, возможно, ОС заменит эти страницы для вас, уменьшив их давление на физическую память.
http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/
Ответ 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