RU | EN | DE

Архитектура JVM — кратко и по делу

Class Loader Subsystem

JVM загружает классы с помощью системы загрузчиков (Class Loaders), которая реализует модель делегирования:

  • Bootstrap ClassLoader – загружает стандартные классы из JDK (rt.jar или модули JDK).
  •   Extension ClassLoader – загружает библиотеки из ext директории.
  • Application ClassLoader – загружает классы из classpath.
  • Пользователь может создать Custom ClassLoader для динамической загрузки (например, в OSGi, плагинах).

Runtime Data Areas

  • Heap – область, где живут все объекты.
  • Method Area (Metaspace) – содержит метаинформацию классов, константный пул.
  • JVM Stack – создается на поток, содержит фреймы вызовов методов.
  • Program Counter Register (PC Register) — это маленький указатель, который хранит номер следующей команды, которую должен выполнить поток.
  • Native Method Stack – стек для вызова нативных методов.

Execution Engine

  • Interpreter – пошаговая интерпретация bytecode.
  • JIT Compiler (Just-In-Time) – компилирует часто используемые методы в машинный код.
  • GC Interface – Execution Engine тесно связана со сборщиком мусора: он должен знать, когда объект больше не используется, и правильно освобождать память.

Delegation Model

Delegation Model (модель делегирования ClassLoader-ов) — это механизм, с помощью которого JVM загружает классы в строгом порядке сверху вниз, чтобы избежать конфликтов и дублирования.

Когда ClassLoader хочет загрузить класс, он сначала делегирует эту задачу своему родителю, и только если родитель не нашёл класс, он загружает его сам.

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

В JVM память делится на несколько областей, и у каждой своя роль

  • Heap (куча)
    • Здесь хранятся экземпляры объектов.
    • Для каждого объекта выделяется место под его поля (данные).
    • Ссылки на объекты тоже создаются, но обычно эти ссылки хранятся в стеке или в полях других объектов на куче.
  • Stack (стек)
    • Здесь хранятся локальные переменные метода, включая ссылки на объекты в куче.
    • Когда метод завершает выполнение, его фрейм из стека удаляется.
  • Metaspace (метаспейс)
    • Здесь хранятся классы и их структура: методы, константы, информация о полях.
    • Не хранит сами экземпляры объектов

Heap

  • Young Generation: o    Eden – новые объекты. o    Survivor Spaces (S0/S1) – промежуточные зоны.
  • Old Generation – объекты, пережившие несколько сборок в Young Gen.

Stack

Каждый поток имеет свой собственный стек, состоящий из фреймов вызова методов. В каждом фрейме хранятся:

  • локальные переменные метода,
  • операндный стек для промежуточных вычислений,
  • ссылка на constant pool класса, чтобы использовать константы и методы этого класса.

Metaspace

  • Что хранится: информация о классах — их метаданные, методы, константы, аннотации.
  • Отличие от PermGen: в Java 8+ PermGen убрали, а Metaspace хранится в нативной памяти, а не в heap. Это позволяет JVM динамически расширять пространство для метаданных без жёсткого лимита (если не задан -XX:MaxMetaspaceSize).
  • Рост и лимиты: растёт по мере загрузки новых классов; можно ограничить через JVM параметры (MaxMetaspaceSizeMetaspaceSize).

Off-heap Memory

Это память, выделяемая вне стандартного heap JVM, напрямую в нативной памяти.

  • Примеры:
    • ByteBuffer.allocateDirect() — прямой буфер для работы с нативной памятью, минуя GC.
    • Пулы нативных ресурсов, кэширование больших данных.
  • Опасности:
    • JVM не отслеживает эту память, поэтому утечки возможны.
    • Неправильное освобождение памяти (DirectByteBuffer) может привести к OutOfMemoryError, даже если heap пустой.

Constant pool

Constant Pool — это специальное место в метаданных класса (часть Method Area в JVM), где хранятся константы, литералы и ссылки на методы/классы.

То есть constant pool — это как шкаф с готовыми вещами, а stack — это стол, на котором ты их раскладываешь для работы.

Garbage collector (CG)

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

В современных JVM один Garbage Collector может использовать разные алгоритмы для разных областей памяти:

  • Copying (копирующий) — применяется в Young Generation. Он быстро копирует живые объекты в новый участок памяти, а все остальное считается мусором.
  • Mark-Sweep-Compact (отметь-удали-компактизируй) — чаще применяется в Old Generation. Сначала помечаются живые объекты (Mark), затем удаляются мусорные (Sweep), и оставшиеся уплотняются (Compact), чтобы избежать фрагментации.

Виды GC

Serial GC

  • Использует один поток для всех фаз GC.
  • Подходит для однопоточных приложений и небольших heap.
  • Алгоритм: “copying” (в Young Gen) и “mark-sweep-compact” (в Old Gen).
  • Параметр: -XX:+UseSerialGC

Parallel GC (Throughput Collector)

  • Использует несколько потоков для работы в Young и Old Gen.
  • Цель — максимальная пропускная способность, а не минимизация пауз.
  • Подходит для серверных приложений без строгих требований к задержкам.
  • Параметр: -XX:+UseParallelGC

CMS (Concurrent Mark Sweep) [устарел]

  • Работает параллельно с приложением (concurrent), уменьшая stop-the-world паузы.
  • Этапы: initial mark, concurrent mark, remark, sweep.
  • Не компактизирует память (может привести к фрагментации).
  • Устарел начиная с Java 9 и удалён в Java 14
  • Параметр: -XX:+UseConcMarkSweepGC

G1 GC (Garbage First)

  • Делит heap на множество регионов.
  • Каждый регион может быть частью Young или Old Generation.
  • Этапы GC включают: Initial Mark, Concurrent Mark, Remark, Cleanup, Copy.
  • Работает по принципу “сборка сначала самых мусорных регионов” (Garbage First).
  • Использует предсказуемые паузы и старается не превышать MaxGCPauseMillis
  • Поддерживает инкрементальную, concurrent и компактизирующую сборку Old Gen.
  • G1 ведёт статистику “полезности” регионов и выбирает наиболее эффективные для сборки.
  • Параметр: -XX:+UseG1GC
  • По умолчанию используется с Java 9+

ZGC (Z Garbage Collector)

  • Поддерживает heap до терабайт.
  • Работает с паузами менее 10 мс, независимо от размера heap.
  • Полностью concurrent (почти все фазы выполняются параллельно с приложением).
  • Подходит для latency-чувствительных систем.
  • Параметр: -XX:+UseZGC

Shenandoah

  • Похож на ZGC, с акцентом на короткие паузы.
  • Использует concurrent compacting.
  • Поддерживается OpenJDK.
  • Параметр: -XX:+UseShenandoahGC

Какой GC по умолчанию в Java

Версия JavaGC по умолчанию
java 8Parallel GC
java 9+G1 GC

Некоторые JDK (например, Azul Zulu) могут использовать ZGC или Shenandoah по умолчанию, если заданы специфичные цели latency

Паузы

  • Stop-the-world – при некоторых фазах GC все потоки приостанавливаются.
  • Minor GC – в Young Generation.
  • Major/Full GC – в Old Generation, может включать очистку Metaspace.

Performance и тюнинг

  • -Xms / -Xmx – минимальный/максимальный размер heap.
  • -Xss – размер стека на поток.
  • -Xss – размер стека на поток.
  • -XX:+PrintGCDetails-Xlog:gc

 JIT (Just-In-Time) компиляция

  • JVM сначала интерпретирует байт-код, но часто выполняемые методы компилируются в нативный машинный код во время работы программы.
  • Позволяет ускорить выполнение, избегая постоянной интерпретации.
  • Оптимизации
    • Inlining — метод “встраивается” в вызывающий код, чтобы убрать накладные расходы на вызов метода.
    • Escape Analysis — анализирует, покидает ли объект метод/поток; если нет — объект может быть размещен в стеке вместо кучи, что снижает нагрузку на GC.

Class Loading и Reflectio

Delegation Model

ClassLoader сначала делегирует загрузку родителю, и лишь потом пытается загрузить сам.

Custom ClassLoaders

Нужны для:

  • плагинов
  • модульных систем (OSGi, Spring Boot)
  • горячей перезагрузки кода

Reflection

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

Типы ссылок в java

Strong Reference (сильная ссылка)

  • Это обычные ссылки, которые мы используем каждый день.
  • Пока на объект существует хотя бы одна сильная ссылка — он не подлежит сборке мусора.
  • Чтобы объект мог быть собран, все сильные ссылки на него должны быть обнулены.
Object obj = new Object();

Soft Reference (мягкая ссылка)

  • Объект удаляется только при нехватке памяти.
  • Используется в кешах, чтобы не загружать память, но сохранить объект, если он ещё полезен.
  • Можно получить объект через ref.get(), но если GC уже удалил его — вернётся null.
SoftReference<Object> ref = new SoftReference<>(new Object());

Weak Reference (слабая ссылка)

  • Объект может быть собран немедленно, даже если только слабые ссылки на него остались.
  • Используется для реализации структур с автоудалением (например, WeakHashMap).
  • Часто применяется, когда объект должен быть доступен «до тех пор, пока он кому-то нужен».
WeakReference<Object> ref = new WeakReference<>(new Object());

Phantom Reference (фантомная ссылка)

  • Объект уже помечен как удаляемый, но ещё не собран GC.
  • Метод get() всегда возвращает **null**.
  • Используется для контроля финализации и освобождения ресурсов вне heap (например, off-heap, native).
  • Требует ReferenceQueue, через которую можно узнать, что объект вот-вот будет удалён.
PhantomReference<Object> ref = new PhantomReference<>(new Object(), referenceQueue);

Итог

Сегодня мы разобрали ключевые аспекты JVM, работу памяти и сборку мусора, которые чаще всего встречаются на собеседованиях по Java. Конечно, не обязательно, что спросят всё из этого списка, но с ним вы сможете уверенно обсуждать эти темы и точно не растеряетесь.