Вопрос 18 · Раздел 3

Что такое параметры -Xms и -Xmx?

→ Без пауз на расширение памяти

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

-Xms и -Xmx — параметры для настройки размера Heap памяти Java.

-Xms — начальный размер Heap (сколько памяти взять при старте) -Xmx — максимальный размер Heap (больше этого не брать)

Пример:

java -Xms512m -Xmx2g MyApp
# Старт: 512 МБ
# Максимум: 2 ГБ

В большинстве production-сценариев: -Xms = -Xmx (предотвращает overhead на resizing). Исключения: CLI-утилиты (маленький -Xms для быстрого старта), memory-constrained среды. → Без пауз на расширение памяти


🟡 Middle Level

Reserved vs Committed

-Xmx4g:
  → JVM резервирует 4 ГБ виртуальной памяти
  → Физическая память выделяется по мере необходимости
  
-Xms4g:
  → Сразу выделяются 4 ГБ физической памяти

Почему -Xms = -Xmx

Если -Xms < -Xmx:
  1. Приложение растёт → нужен больший Heap
  2. JVM пытается избежать расширения: сначала запускает GC, чтобы освободить место в текущем Heap.
     В современных GC (G1) это обычно Young/Mixed GC, а не Full GC.
     Но если GC не помог — JVM запрашивает больше памяти у ОС.
  3. Пауза!
  4. Расширение → системный вызов
  
Если -Xms = -Xmx:
  → Нет пауз на ресайз
  → Стабильные пороги GC
  → Предсказуемое поведение

Docker/Kubernetes

# Современный подход (Java 11+):
-XX:InitialRAMPercentage=75.0
-XX:MaxRAMPercentage=75.0

# JVM читает лимит контейнера
# → 75% от RAM контейнера = Heap
# → Гибко: меняете лимит в YAML → Heap меняется

AlwaysPreTouch

-XX:+AlwaysPreTouch

# При старте: физически выделить все страницы
# → Старт дольше
# → Нет микро-задержек при первом обращении
# → Гарантировано, что память выделена

🔴 Senior Level

Transparent Huge Pages (THP)

Linux: Huge Pages = 2 МБ вместо 4 КБ
  → Меньше TLB misses
  → +5-10% производительности
  
Проблема: THP конфликтует с G1
  → Длинные паузы GC
  
Решение:
  1. Отключить THP на уровне ядра
  2. Использовать статические Huge Pages:
     -XX:+UseLargePages

Native Memory = не только Heap

RSS (общая память процесса) =
  Heap (-Xmx)
  + Metaspace
  + Code Cache
  + Thread Stacks (-Xss × потоки)
  + Direct Buffers
  + GC Overhead
  
→ -Xmx30g на 32 ГБ сервере = OOM Killer!
→ Оставляйте 20-30% на Native Memory

NMT (Native Memory Tracking)

-XX:NativeMemoryTracking=summary

jcmd <pid> VM.native_memory summary

# Покажет:
# Java Heap: 30 GB
# Class: 50 MB
# Thread: 100 MB
# Code: 80 MB
# GC: 200 MB
# Internal: 50 MB
# ...

Best Practices

  1. -Xms = -Xmx в production
  2. RAMPercentage для контейнеров
  3. AlwaysPreTouch для стабильности
  4. Оставляйте 20-30% на Native Memory
  5. NMT для мониторинга
  6. Избегайте THP с G1
  7. Не ставьте -Xmx впритык к RAM

Резюме для Senior

  • -Xms = -Xmx = без пауз на ресайз
  • RAMPercentage = гибкость в контейнерах
  • AlwaysPreTouch = нет page fault задержек
  • RSS > -Xmx = Native Memory учитывайте
  • NMT = мониторинг всей памяти
  • THP = осторожно с G1
  • OOM Killer = если -Xmx слишком близок к RAM

🎯 Шпаргалка для интервью

Обязательно знать:

  • -Xms — начальный размер Heap, -Xmx — максимальный; в production -Xms = -Xmx для предотвращения пауз на ресайз
  • Reserved vs Committed: -Xmx резервирует виртуальную память; -Xms сразу выделяет физическую
  • При расширении Heap (-Xms < -Xmx): JVM сначала запускает GC → если не помог → системный вызов к ОС → пауза
  • Docker/Kubernetes: -XX:InitialRAMPercentage=75.0 / -XX:MaxRAMPercentage=75.0 — JVM читает лимит контейнера
  • AlwaysPreTouch: при старте физически выделить все страницы → старт дольше, но нет микро-задержек при первом обращении
  • RSS = Heap + Metaspace + Code Cache + Thread Stacks + Direct Buffers + GC Overhead; оставляйте 20-30% RAM на Native Memory
  • Transparent Huge Pages (THP): +5-10% производительности, но конфликтует с G1 → длинные паузы

Частые уточняющие вопросы:

  • Почему -Xms = -Xmx в production? — Без пауз на расширение Heap; стабильные пороги GC; предсказуемое поведение
  • Что будет, если поставить -Xmx30g на 32 ГБ сервере? — OOM Killer убьёт процесс: RSS > 32 ГБ (Metaspace + Stacks + Code Cache ещё 2-4 ГБ)
  • Зачем AlwaysPreTouch? — Предотвращает page fault задержки при первом обращении к страницам; гарантирует, что память реально выделена
  • Почему THP конфликтует с G1? — G1 использует регионы разного размера; THP (2 МБ страницы) вызывает фрагментацию → долгие паузы GC

Красные флаги (НЕ говорить):

  • «-Xmx — это вся память процесса» — RSS значительно больше: Metaspace, Stacks, Code Cache, Direct Buffers
  • «THP всегда улучшает производительность» — конфликтует с G1; отключайте или используйте статические Huge Pages
  • «В контейнере JVM автоматически использует весь лимит» — без RAMPercentage JVM видит хост, а не контейнер (Java 8 без патчей)

Связанные темы:

  • [[1. В чём разница между Heap и Stack]]
  • [[2. Что хранится в Heap]]
  • [[19. Что произойдёт при OutOfMemoryError]]
  • [[22. Какие инструменты помогают анализировать память]]
  • [[11. Что такое Metaspace (или PermGen)]]