Поделиться через


Управление памятью Java

Примечание.

Планы Basic, Standardи Enterprise вступили в период вывода из обращения 17 марта 2025 года. Дополнительные сведения см. в объявлении о выходе на пенсию в Azure Spring Apps.

Эта статья относится к:✅ 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

Существует три термина в отношении сборки мусора Java (GC): "Младшая GC", "Старшая GC" и "Полная GC". Эти термины не четко определены в спецификации JVM. Здесь мы считаем "Основной GC" и "Полный GC" эквивалентными.

Незначительный GC выполняется при заполнении пространства Eden. Он удаляет все мертвые объекты в молодом поколении и перемещает живые объекты из пространства Eden в s1 пространства выживших, или из s1 в s2.

Полная или основная сборка мусора выполняет очистку всей кучи. Полный GC может также собирать такие части, как метапространство и прямая память, которые можно очистить только с помощью полного GC.

Максимальный размер кучи влияет на частоту младших сборок мусора и полных сборок мусора (Garbage Collection, GC). Максимальное метапространство и максимальный размер прямой памяти влияют на полную сборку данных.

Если задать максимальный размер кучи более низким значением, сборки мусора происходят чаще, что замедлит приложение немного, но лучше ограничивает использование памяти. Если задать максимальный размер кучи более высоким значением, сборки мусора происходят реже, что может привести к большему риску нехватки памяти (OOM). Для получения дополнительной информации см. раздел "Типы проблем с переполнением памяти" в документе "Проблемы перезапуска приложения, вызванные переполнением памяти".

Метапространство и прямая память могут быть собраны только с помощью полного сборщика мусора. Когда метапространство или прямая память заполнена, будет выполняться полная сборка данных.

Конфигурации памяти Java

В следующих разделах описываются важные аспекты конфигурации памяти Java.

Контейнеризация Java

Приложения в Azure Spring Apps выполняются в средах контейнеров. Дополнительные сведения см. в разделе "Контейнеризация приложений Java".

Важные параметры JVM

Максимальный размер каждой части памяти можно настроить с помощью параметров JVM. Параметры JVM можно задать с помощью команд Azure CLI или с помощью портал Azure. Дополнительные сведения см. в разделе «Изменение конфигураций для устранения проблем» в средствах для устранения проблем с памятью.

В следующем списке описаны параметры JVM:

  • Конфигурация размера кучи

    • -Xms задает начальный размер кучи по абсолютному значению.
    • -Xmx задает максимальный размер кучи по абсолютному значению.
    • -XX:InitialRAMPercentage задает начальный размер кучи в процентах от размера кучи или размера памяти приложения.
    • -XX:MaxRAMPercentage задает максимальный размер кучи в процентах от размера кучи или размера памяти приложения.
  • Настройка размера прямой памяти

    • -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, внутренний знак и другое
  • Прямая память: рекомендуемое ежедневное использование составляет 10МБ-200МБ.

На следующей схеме показаны те же сведения. Числа в сером цвете — это эталонные значения использования ежедневной памяти.

Схема типичного макета памяти для приложений размером 2 ГБ.

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

Java OOM

OOM означает, что у приложения заканчивается память. Существует два разных понятия: OOM контейнера и OOM JVM. Для получения дополнительной информации см. проблемы с перезапуском приложений, вызванные недостатком памяти.

См. также