Управление памятью Java
Примечание.
Планы "Базовый", "Стандартный" и "Корпоративный" будут устарели начиная с середины марта 2025 г. с 3-летнего периода выхода на пенсию. Рекомендуется перейти в приложения контейнеров Azure. Дополнительные сведения см. в объявлении о выходе на пенсию в Azure Spring Apps.
Стандартный план потребления и выделенного плана будет устарел с 30 сентября 2024 г. с полным завершением работы после шести месяцев. Рекомендуется перейти в приложения контейнеров Azure. Дополнительные сведения см. в статье "Миграция потребления Azure Spring Apps Standard" и выделенного плана в приложения контейнеров Azure.
Эта статья относится к: ✔️ Basic/Standard ❌ Enterprise
В этой статье описаны различные понятия, связанные с управлением памятью Java, которые помогают понять поведение приложений Java, размещенных в Azure Spring Apps.
Модель памяти Java
Память приложения Java состоит из нескольких частей, и существуют различные способы разделения частей. В этой статье рассматривается память Java, разделенная на кучи памяти, не кучи и прямую память.
Память кучи
Кучи хранят все экземпляры классов и массивы. Каждая виртуальная машина Java (JVM) имеет только одну область кучи, которая предоставляет общий доступ между потоками.
Spring Boot Actuator может наблюдать за значением памяти кучи. Spring Boot Actuator принимает значение кучи jvm.memory.used/committed/max
в составе . Дополнительные сведения см. в разделе jvm.memory.used/committed/max в средствах для устранения проблем с памятью.
Кучи память делится на молодое поколение и старое поколение. Эти термины описаны в следующем списке, а также связанные термины.
Молодое поколение: все новые объекты выделяются и возрастом в молодом поколении.
- Пространство Eden: новые объекты выделяются в пространстве Eden.
- Пространство выживших: объекты будут перемещены из Эдена в выживший космос после выживания одного цикла сборки мусора. Пространство выживших можно разделить на две части: s1 и s2.
Старое поколение: также называется место пребывания в должности. Объекты, оставшиеся в выживших пространствах в течение длительного времени, будут перемещены в старое поколение.
До Java 8 другой раздел, называемый постоянным поколением , также был частью кучи. Начиная с Java 8, постоянное поколение было заменено метапространством в памяти без кучи.
Память без кучи
Память без кучи делится на следующие части:
Часть памяти без кучи, которая заменила постоянное поколение (или permGen) начиная с Java 8. Spring Boot Actuator наблюдает этот раздел и принимает его как часть
jvm.memory.used/committed/max
. Другими словами,jvm.memory.used/committed/max
это сумма памяти кучи и бывшая часть permGen в памяти, отличной от кучи. Прежнее постоянное поколение состоит из следующих частей:- Метапространство, в котором хранятся определения классов, загруженные загрузчиками классов.
- Сжатое пространство класса, которое предназначено для сжатых указателей класса.
- Кэш кода, в котором хранится машинный код, скомпилированный JIT.
Другая память, например стек потоков, которая не наблюдается в Spring Boot Actuator.
Прямая память
Прямая память — это собственная память, выделенная java.nio.DirectByteBuffer
в сторонних библиотеках, таких как nio и gzip.
Spring Boot Actuator не наблюдает значения прямой памяти.
На следующей схеме представлена модель памяти Java, описанная в предыдущем разделе.
Сборка мусора Java
Существует три термина в отношении сборки мусора Java (GC): "Дополнительная сборка GC", "Основная сборка сборок" и "Полная сборка мусора". Эти термины не четко определены в спецификации JVM. Здесь мы считаем, что "Основные GC" и "Full GC" будут эквивалентны.
Незначительный GC выполняется при заполнении пространства Eden. Он удаляет все мертвые объекты в молодом поколении и перемещает живые объекты в пространство Eden в s1 из пространства выживших или из s1 на s2.
Полная сборка мусора или основная сборка мусора выполняет сборку мусора во всей куче. Полный GC также может собирать такие части, как метапространство и прямую память, которые можно очистить только с помощью полной сборки GC.
Максимальный размер кучи влияет на частоту незначительных сборок и полной сборки GC. Максимальное метапространство и максимальный размер прямой памяти влияют на полную сборку данных.
Если задать максимальный размер кучи более низким значением, сборки мусора происходят чаще, что замедлит приложение немного, но лучше ограничивает использование памяти. Если задать максимальный размер кучи более высоким значением, сборки мусора происходят реже, что может привести к большему риску нехватки памяти (OOM). Дополнительные сведения см. в разделе "Типы проблем вне памяти" о проблемах перезапуска приложения, вызванных проблемами без памяти.
Метапространство и прямая память можно собирать только с помощью полной сборки мусора. Когда метапространство или прямая память заполнена, будет выполняться полная сборка данных.
Конфигурации памяти Java
В следующих разделах описываются важные аспекты конфигурации памяти Java.
Контейнеризация Java
Приложения в Azure Spring Apps выполняются в средах контейнеров. Дополнительные сведения см. в разделе "Контейнеризация приложений Java".
Важные параметры JVM
Максимальный размер каждой части памяти можно настроить с помощью параметров JVM. Параметры JVM можно задать с помощью команд Azure CLI или с помощью портал Azure. Дополнительные сведения см. в разделе "Изменение конфигураций" для устранения проблем с средствами для устранения проблем с памятью.
В следующем списке описаны параметры JVM:
Конфигурация размера кучи
-Xms
задает начальный размер кучи по абсолютному значению.-Xmx
задает максимальный размер кучи по абсолютному значению.-XX:InitialRAMPercentage
задает начальный размер кучи в процентах от размера кучи или размера памяти приложения.-XX:MaxRAMPercentage
задает максимальный размер кучи в процентах от размера кучи или размера памяти приложения.
Настройка размера памяти direct
-XX:MaxDirectMemorySize
задает максимальный размер прямой памяти по абсолютному значению. Дополнительные сведения см . в статье MaxDirectMemorySize в документации Oracle.
Конфигурация размера метапространства
-XX:MaxMetaspaceSize
задает максимальный размер метапространства по абсолютному значению.
Максимальный размер памяти по умолчанию
В следующих разделах описывается, как заданы максимальные размеры памяти по умолчанию.
Максимальный размер кучи по умолчанию
Azure Spring Apps задает максимальный размер памяти кучи по умолчанию примерно на 50%-80 % памяти приложения для приложений Java. В частности, Azure Spring Apps использует следующие параметры:
- Если память < приложения составляет 1 ГБ, максимальный размер кучи по умолчанию составляет 50 % памяти приложения.
- Если 1 ГБ = память < приложения 2 ГБ<, максимальный размер кучи по умолчанию составляет 60 % памяти приложения.
- Если 2 ГБ <= память < приложения 3 ГБ, максимальный размер кучи по умолчанию составляет 70 % памяти приложения.
- Если 3 ГБ <= память приложения, максимальный размер кучи по умолчанию составляет 80 % памяти приложения.
Максимальный размер прямой памяти по умолчанию
Если максимальный размер прямой памяти не задан с помощью параметров JVM, JVM автоматически устанавливает максимальный размер прямой памяти для значения, возвращаемого runtime.getRuntime.maxMemory(). Это значение приблизительно равно максимальному размеру памяти кучи. Дополнительные сведения см. в файле JDK 8 VM.java.
Макет использования памяти
Размер кучи зависит от пропускной способности. В основном при настройке можно сохранить максимальный размер кучи по умолчанию, что оставляет разумную память для других частей.
Размер метапространства зависит от сложности кода, например числа классов.
Размер прямой памяти зависит от пропускной способности и использования сторонних библиотек, таких как nio и gzip.
В следующем списке описывается типичный пример макета памяти для приложений размером 2 ГБ. Этот список можно использовать для настройки параметров размера памяти.
- Общая память (2048M)
- Память кучи: Xmx составляет 1433,6 млн (70 % общей памяти). Эталонное значение ежедневного использования памяти — 1200M.
- Молодое поколение
- Пространство выживших (S0, S1)
- Пространство Эдена
- Старое поколение
- Молодое поколение
- Память без кучи
- Наблюдаемая часть (наблюдаемая Spring Boot Actuator)
- Метапространство: значение ссылки на ежедневное использование — 50M-256M
- Кэш кода
- Сжатое пространство класса
- Не наблюдаемая часть (не наблюдаемая Spring Boot Actuator): ежедневное значение ссылки на использование составляет 150M-250M.
- Стек потоков
- GC, внутренний символ и другие
- Наблюдаемая часть (наблюдаемая Spring Boot Actuator)
- Прямая память: значение ссылки на ежедневное использование — 10M-200M.
На следующей схеме показаны те же сведения. Числа в сером цвете — это эталонные значения использования ежедневной памяти.
В целом при настройке максимальных размеров памяти следует учитывать использование каждой части в памяти, а сумма всех максимальных размеров не должна превышать общую доступную память.
Java OOM
OOM означает, что приложение выходит за пределы памяти. Существует два разных понятия: OOM контейнера и OOM JVM. Дополнительные сведения см. в статье о проблемах перезапуска приложений, вызванных проблемами без памяти.