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


Управление памятью 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

Существует три термина в отношении сборки мусора 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, внутренний символ и другие
  • Прямая память: значение ссылки на ежедневное использование — 10M-200M.

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

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

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

Java OOM

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

См. также