Сборщик мусора Java ZGC ИСПОЛЬЗУЕТ много памяти
Я создал простое приложение с помощью Springboot. Сборщик мусора ZGC, который я использую при развертывании на сервере Linux, ИСПОЛЬЗУЕТ много памяти.. Я пытался ограничить максимальную память кучи до 500 МБ с помощью Xmx500m, но программа JAVA по-прежнему использовала более 1 ГБ. Когда я использовал сборщик G1, он использовал только 350 МБ. Я не знаю почему, это ОШИБКА JDK11? Или у меня проблема с параметрами загрузки? ####Среда выполнения
- операционная система: CentOS Linux, выпуск 7.8.2003
- Версия JDK: jdk11
- версия springboot: v2.3.0.RELEASE Вот моя команда запуска Java
java -Xms128m -Xmx500m \
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC \
-jar app.jar
Вот скриншот использования памяти во время выполнения
Использование памяти кучи https://github.com/JoyfulAndSpeedyMan/assets/blob/master/2020-07-13%20201259.png?raw=true
Использование системной памяти https://github.com/JoyfulAndSpeedyMan/assets/blob/master/2020-07-13%20201357.png?raw=true
Вот что происходит, когда вы используете команду запуска Java сборщика мусора по умолчанию
java -Xms128m -Xmx500m \
-jar app.jar
Использование памяти кучи https://github.com/JoyfulAndSpeedyMan/assets/blob/master/2020-07-13%20202442.png?raw=true
Использование системной памяти https://github.com/JoyfulAndSpeedyMan/assets/blob/master/2020-07-13%20202421.png?raw=true
По умолчанию jdk11 ИСПОЛЬЗУЕТ сборщик мусора G1. Теоретически, не должно ли G1 потреблять больше памяти, чем ZGC? Почему я не использовал его таким образом? Я неправильно понял? Поскольку я новичок в JVM, я не понимаю, почему.
4 ответа
ZGC использует технику, известную как цветные указатели. Идея состоит в том, чтобы использовать некоторые свободные биты в 64-битных указателях в куче для встроенных метаданных. Однако при разыменовании таких указателей эти биты необходимо замаскировать, что подразумевает дополнительную работу для JVM.
Чтобы избежать накладных расходов на указатели маскирования, ZGC использует технику множественного отображения. Мульти-отображение - это когда несколько диапазонов виртуальной памяти отображаются в один и тот же диапазон физической памяти.
ZGC использует 3 вида кучи Java ("Mark0", "Mark1", "remapped"), то есть 3 разных "цвета" указателей кучи и 3 отображения виртуальной памяти для одной и той же кучи.
Как следствие, операционная система может сообщать о 3-кратном увеличении использования памяти. Например, для кучи 512 МБ заявленная выделенная память может достигать 1,5 ГБ, не считая памяти, кроме кучи. Примечание. Многовариантность влияет на сообщаемый объем используемой памяти, но физически куча по-прежнему будет использовать 512 МБ ОЗУ. Иногда это приводит к забавному эффекту: RSS процесса выглядит больше, чем объем физической памяти.
Смотрите также:
JVM использует гораздо больше, чем просто память кучи - прочтите этот отличный ответ, чтобы лучше понять потребление памяти JVM: Java использует гораздо больше памяти, чем размер кучи (или правильно размер ограничения памяти Docker)
Вам нужно выйти за рамки проверки кучи и использовать такие вещи, как отслеживание собственной памяти, чтобы получить более четкую картину.
Я не знаю, в чем конкретно проблема вашего приложения, но ZGC часто упоминается как хороший для больших куч. Это также совершенно новый сборщик, в который недавно внесено много изменений - я бы обновился до JDK 14, если вы хотите его использовать (см. "Журнал изменений" здесь: https://wiki.openjdk.java.net/display/zgc/Main)
Объем памяти ОС, который использует JVM (т. Е. «Зафиксированная куча»), зависит от того, как часто запускается сборщик мусора (а также от того, освобождает ли он ненужную память, если приложение начинает использовать меньше), что является настраиваемым параметром. К сожалению, ZGC (в настоящее время) не так агрессивен в этом по умолчанию, как G1, но у обоих есть некоторые параметры настройки, которые вы можете попробовать.
PS Как отмечали другие, столбец RES htop вводит в заблуждение, но диаграмма VisualVM показывает реальную картину.
Это результат компромисса между пропускной способностью, задержкой и размером занимаемой площади. Выбирая между этими 3 вещами, вы можете выбрать только 2.
ZGC - это параллельный сборщик мусора с малым временем паузы. Поскольку вы не хотите отказываться от пропускной способности, вы жертвуете задержкой и пропускной способностью на размер. Так что ничего удивительного в таком большом потреблении памяти нет.
G1 не является сборщиком с малой паузой, поэтому вы переносите этот компромисс в сторону занимаемой площади и получаете большее время паузы, но выигрываете немного памяти.