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

Как связаны данные в памяти JVM?

2.3 Middle🔥 131 комментариев
#ORM и Hibernate

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

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

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

Связь данных в памяти JVM: полный разбор

Понимание того, как данные организованы в памяти JVM — один из ключевых навыков для Java-разработчика, особенно при оптимизации производительности и отладке утечек памяти. Давайте разберемся подробно.

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

Память JVM состоит из нескольких основных частей:

1. Heap (Куча)

Большая часть памяти, где хранятся объекты. Управляется сборщиком мусора (GC).

String name = "John";  // Переменная name на Stack, объект на Heap
User user = new User();  // Ссылка на Stack, объект на Heap

2. Stack (Стек)

Хранит примитивные значения и ссылки на объекты. Каждый поток имеет свой Stack. Память освобождается автоматически при выходе из scope.

public void example() {
    int age = 25;              // примитив - на Stack
    String name = "Alice";     // ссылка на Stack, строка на Heap
}  // age и name удаляются со Stack

3. Метаспейс (Method Area)

Хранит информацию о классах, методах, статических переменных и константах. В Java 8+ это offheap память.

public class Car {  // информация о классе в Метаспейсе
    static String company = "Toyota";  // статическая переменная
}

Как объекты связаны в памяти

Пример 1: Простые ссылки

class Address {
    String city;
    Address(String city) { this.city = city; }
}

class Person {
    String name;
    Address address;  // ссылка на другой объект
    
    Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
}

public static void main(String[] args) {
    Address addr = new Address("Moscow");  // объект на Heap
    Person person = new Person("Bob", addr);  // ссылка на addr
    
    // На Heap: Person объект содержит ссылку на Address объект
    // На Stack: person и addr - это переменные-ссылки
}

Визуально в памяти:

Stack:                     Heap:
┌─────────────────┐       ┌──────────────────┐
│ person  ┼──────┼──────>│ Person object    │
│ (ref)   │       │       │  name: "Bob"     │
└─────────────────┘       │  address ┼───┐  │
│ addr    ┼───┐   │       │          │   │  │
│ (ref)   │   │   │       └──────────┼──┼──┘
└─────────────────┘       │          │  │
                          │          v  │
                          │  ┌──────────────────┐
                          │  │ Address object   │
                          └─>│  city: "Moscow"  │
                             └──────────────────┘

Пример 2: Коллекции и массивы

List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");

// На Heap:
// - ArrayList объект (содержит ссылку на внутренний массив)
// - Внутренний массив (содержит ссылки на String объекты)
// - String объекты "Alice" и "Bob"

Пример 3: Графовые структуры

class Node {
    int value;
    Node next;
    Node prev;
    
    Node(int value) { this.value = value; }
}

// Связный список
Node node1 = new Node(1);
Node node2 = new Node(2);
node1.next = node2;  // node1 ссылается на node2
node2.prev = node1;  // node2 ссылается обратно на node1 (циклическая ссылка)

Важно: Циклические ссылки не создают утечку памяти — GC их обнаруживает.

Типы данных и их расположение

ТипРасположениеПример
ПримитивStackint x = 5;
ОбъектHeap (ссылка на Stack)String s = new String();
Статическая переменнаяМетаспейсstatic int counter = 0;
Массив примитивовHeap (данные) + Stack (ссылка)int[] arr = new int[10];
Массив объектовHeap (массив + ссылки)String[] names = new String[5];

Сборка мусора и связи объектов

GC использует граф объектов для определения, какие объекты достижимы:

public static void main(String[] args) {
    Person person = new Person("Alice", new Address("London"));
    // GC видит: person -> Address объект (достижимы)
    
    person = null;  // Удалили ссылку
    // GC видит: Person и Address объекты больше недостижимы
    // Они будут удалены на следующей сборке мусора
}

Слабые ссылки (Weak References)

Когда нужно, чтобы объект был собран сборщиком мусора, даже если на него есть ссылка:

WeakReference<String> weakRef = new WeakReference<>(new String("temp"));

if (weakRef.get() != null) {
    System.out.println("Объект ещё в памяти");
} else {
    System.out.println("Объект удалён GC");
}

Общие ошибки при работе со ссылками

Утечка памяти через статические ссылки

// ПЛОХО: утечка памяти
public class Cache {
    private static List<Data> cache = new ArrayList<>();  // Статическая ссылка
    
    public static void addData(Data d) {
        cache.add(d);  // Объекты никогда не удаляются!
    }
}

// ХОРОШО: используем WeakHashMap
public class Cache {
    private static Map<String, Data> cache = new WeakHashMap<>();
}

Забытые ссылки в коллекциях

// ПЛОХО
List<String> list = new ArrayList<>();
list.add("element");
// список забыт, но объект сохраняется, пока существует list

// ХОРОШО
list.clear();  // очищаем перед удалением ссылки
list = null;

Заключение

Данные в памяти JVM связаны через граф объектов:

  • Stack хранит примитивы и ссылки
  • Heap хранит сами объекты
  • GC отслеживает достижимость объектов через граф ссылок
  • Циклические ссылки не проблема для GC
  • Слабые ссылки используются для специальных случаев

Понимание этой архитектуры критично для написания эффективного и безопасного кода.

Как связаны данные в памяти JVM? | PrepBro