Какие основные области памяти (Memory Areas) существуют в JVM и для чего они предназначены?

«Какие основные области памяти (Memory Areas) существуют в JVM и для чего они предназначены?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

JVM (Java Virtual Machine) разделяет память на несколько областей, каждая из которых имеет строго определенное назначение в жизненном цикле программы.

Основные области памяти JVM:

  1. Heap (Куча):

    • Назначение: Хранение всех объектов (экземпляров классов) и массивов, созданных во время выполнения программы (оператор new).
    • Особенности: Общая для всех потоков. Управляется Сборщиком Мусора (Garbage Collector, GC). Разделяется на поколения (Young, Old) для оптимизации GC.
  2. Stack (Стек):

    • Назначение: Хранение локальных переменных (примитивных типов и ссылок на объекты в куче), вызовов методов и частичных результатов. Создается отдельно для каждого потока.
    • Особенности: Быстрый доступ (LIFO), ограниченный размер. Переполнение приводит к StackOverflowError. Каждый вызов метода создает новый кадр стека (stack frame).
  3. Method Area (Область Методов / Metaspace):

    • Назначение: Хранение метаданных классов: структура класса, байт-код методов, статические переменные (static), константы пула строк (String Pool), информация для рефлексии.
    • Особенности: В современных JVM (Java 8+) называется Metaspace и, как правило, выделяется из native-памяти (не из Heap).
  4. Program Counter (PC) Register (Регистр Счетчика Команд):

    • Назначение: Хранение адреса текущей выполняемой инструкции JVM для каждого потока. Если выполняется native-метод, значение не определено.
  5. Native Method Stack:

    • Назначение: Поддержка вызовов нативных методов (написанных на C/C++ через JNI). Создается для каждого потока.

Пример распределения:

public class MemoryExample {
    private static int staticVar = 100; // Method Area (Metaspace)
    private int instanceVar;            // Heap (в составе объекта)

    public void calculate(int param) {  // Байт-код метода — Method Area
        int localVar = param * 2;       // Stack (в кадре метода calculate)
        Object obj = new Object();      // Ссылка 'obj' — в Stack, сам Object — в Heap
        System.out.println(localVar);
    }
}