Питання 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)]]