← Назад к вопросам

Как выполняется область данных в JVM

3.0 Senior🔥 151 комментариев
#JVM и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Как выполняется область данных в JVM

"Область данных" (Memory Areas) в JVM — это совокупность областей памяти, используемых при выполнении программ. JVM структурирует память на несколько независимых областей, каждая из которых имеет свою ответственность.

Структура памяти в JVM

JVM Memory
├── Heap (куча)
│   ├── Young Generation
│   │   ├── Eden
│   │   ├── Survivor 0
│   │   └── Survivor 1
│   └── Old Generation
├── Stack (стек)
│   ├── JVM Stack (для каждого потока)
│   └── Native Method Stack
├── Metaspace (Java 8+)
├── Program Counter Register
└── Class/Method Area (Java 7 и ранее — Permanent Generation)

1. Heap (Куча)

Основная область для хранения объектов. Общая для всех потоков, управляется сборщиком мусора.

public class HeapExample {
    public static void main(String[] args) {
        // Создание объектов в Heap
        String name = "John";      // Объект String → Heap
        User user = new User();    // Объект User → Heap
        List<String> list = new ArrayList<>();  // ArrayList → Heap
        
        // Примитивные типы в методе → Stack
        int age = 25;              // int → Stack (локальная переменная)
    }
}

// Визуально:
// Heap: [String("John")] [User объект] [ArrayList объект]
// Stack: [name] [user] [list] [age]

Характеристики Heap:

  • Размер: определяется -Xms (начальный) и -Xmx (максимальный)
  • Общая память: все потоки имеют доступ
  • Сборка мусора: автоматическое удаление неиспользуемых объектов
  • Скорость: медленнее чем Stack
# Конфигурация Heap
java -Xms256m -Xmx2g MyApplication
# -Xms = начальный размер 256MB
# -Xmx = максимальный размер 2GB

2. Stack (Стек)

Основная область для локальных переменных и ссылок на объекты. Создаётся отдельный стек для каждого потока.

public class StackExample {
    public void calculate() {
        int x = 10;      // Stack
        int y = 20;      // Stack
        int result = x + y;  // Stack
        
        // Все примитивные типы и ссылки → Stack
    }
    
    public static void main(String[] args) {
        StackExample example = new User();  // Ссылка 'example' → Stack
                                             // Объект User → Heap
    }
}

// Stack структура (Last In, First Out — LIFO):
// При вызове calculate():
// ┌─────────┐
// │ result  │ ← вершина стека
// │ y       │
// │ x       │
// └─────────┘

Характеристики Stack:

  • Размер: определяется -Xss
  • Локальный: отдельный стек для каждого потока
  • LIFO: последний вошёл — первый вышел
  • Скорость: очень быстро (просто указатель на вершину)
  • Исключения: StackOverflowError при переполнении
# Конфигурация Stack
java -Xss1m MyApplication
# Размер стека для каждого потока: 1MB

3. Metaspace (Java 8+)

Область памяти для метаданных класса, метода, поля и т.д. В Java 7 это была Permanent Generation в Heap.

public class MetaspaceExample {
    public static void main(String[] args) {
        // Информация о классе User → Metaspace
        // Байт-код метода → Metaspace
        // Константы класса → Metaspace
        
        User user = new User();  // Сам объект → Heap
    }
}

// Metaspace содержит:
// - Class definitions
// - Method code (bytecode)
// - Constant pool
// - Field data
// - Method data

Характеристики Metaspace:

  • Размер: автоматический (может расти)
  • Native memory: использует память ОС, не Heap
  • Нет GC: удаляется только при выгрузке класса
  • Исключения: OutOfMemoryError: Metaspace при переполнении
# Конфигурация Metaspace
java -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=256m MyApplication

4. Program Counter (PC) Register

Маленькая область памяти для каждого потока, содержит адрес текущей выполняемой инструкции JVM.

public class ProgramCounterExample {
    public void execute() {
        int a = 5;    // PC: адрес этой инструкции
        int b = 10;   // PC: адрес этой инструкции
        int c = a + b;  // PC: адрес этой инструкции
    }
}

// PC регистр:
// При выполнении execute():
// PC = 0x1000 → bytecode инструкция 1
// PC = 0x1002 → bytecode инструкция 2
// PC = 0x1004 → bytecode инструкция 3

5. Native Method Stack

Область памяти для native методов (написаны на C/C++).

public class NativeMethodExample {
    // Native метод (реализация в C/C++)
    public native void printSystemInfo();
    
    static {
        System.loadLibrary("nativelib");
    }
    
    public static void main(String[] args) {
        NativeMethodExample example = new NativeMethodExample();
        example.printSystemInfo();  // Выполняется в Native Method Stack
    }
}

Практический пример: отслеживание памяти

public class MemoryTracking {
    public static void main(String[] args) {
        // Получить Runtime
        Runtime runtime = Runtime.getRuntime();
        
        System.out.println("=== До создания объектов ===");
        printMemoryInfo(runtime);
        
        // Создаём много объектов
        List<byte[]> bigObjects = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            bigObjects.add(new byte[1024 * 1024]);  // 1MB каждый
        }
        
        System.out.println("\n=== После создания объектов ===");
        printMemoryInfo(runtime);
        
        // Очистить и получить память
        bigObjects.clear();
        System.gc();
        
        System.out.println("\n=== После очистки ===");
        printMemoryInfo(runtime);
    }
    
    private static void printMemoryInfo(Runtime runtime) {
        long totalMemory = runtime.totalMemory();      // Всего выделено
        long freeMemory = runtime.freeMemory();        // Свободной памяти
        long maxMemory = runtime.maxMemory();          // Максимум возможное
        long usedMemory = totalMemory - freeMemory;    // Использовано
        
        System.out.printf("Max Memory: %d MB%n", maxMemory / (1024 * 1024));
        System.out.printf("Total Memory: %d MB%n", totalMemory / (1024 * 1024));
        System.out.printf("Used Memory: %d MB%n", usedMemory / (1024 * 1024));
        System.out.printf("Free Memory: %d MB%n", freeMemory / (1024 * 1024));
    }
}

Поток выполнения в памяти

public class ExecutionFlow {
    private static int globalCounter = 0;  // Metaspace (static поле класса)
    
    public void processData() {
        int localVar = 5;           // Stack
        String name = "John";       // 'name' ссылка → Stack
                                    // "John" объект → Heap
        User user = new User();     // 'user' ссылка → Stack
                                    // User объект → Heap
                                    // User.class info → Metaspace
        
        List<String> names = new ArrayList<>();  // 'names' → Stack
                                                   // ArrayList → Heap
        names.add(name);
    }
}

// Визуально:
// ┌─ Metaspace ──────────────────────────────┐
// │ ExecutionFlow.class                       │
// │ processData() method bytecode             │
// │ globalCounter (static field metadata)     │
// └──────────────────────────────────────────┘
//
// ┌─ Stack (при вызове processData()) ───────┐
// │ localVar = 5                              │
// │ name → [ref to Heap]                      │
// │ user → [ref to Heap]                      │
// │ names → [ref to Heap]                     │
// └──────────────────────────────────────────┘
//
// ┌─ Heap ───────────────────────────────────┐
// │ "John" (String object)                    │
// │ User { ... } (User object)                │
// │ ArrayList [ "John" ]                      │
// └──────────────────────────────────────────┘

Проблемы памяти

1. OutOfMemoryError: Java heap space

// Heap переполнен
List<byte[]> list = new ArrayList<>();
while (true) {
    list.add(new byte[1024 * 1024]);  // Бесконечное выделение памяти
}

2. StackOverflowError

// Бесконечная рекурсия
public void recurse() {
    recurse();  // Stack переполняется
}

3. Memory Leak (утечка памяти)

private static List<String> leakingList = new ArrayList<>();

public void processData(String data) {
    leakingList.add(data);  // Данные никогда не удаляются (static ссылка)
}

Резюме

Области данных в JVM:

ОбластьНазначениеОбщаяGCРазмер
HeapОбъектыДаДа-Xms, -Xmx
StackЛокальные переменныеНетНет-Xss
MetaspaceМетаданные классовДаНетAuto
PC RegisterАдрес инструкцииНетНетМалая
Native StackNative методыНетНетВарьируется

Понимание этих областей критично для:

  • Оптимизации производительности
  • Отладки проблем с памятью
  • Конфигурации JVM
  • Понимания сборки мусора