Короткий ответ
Стек создаётся для каждого потока отдельно и хранит кадры методов: локальные переменные, параметры и служебную информацию; работает по принципу LIFO. Куча — общая для всех потоков область, в которой размещаются объекты и массивы, созданные через new. Локальные переменные-примитивы хранятся в стеке; если примитив — поле объекта, он лежит в куче вместе с объектом.
Как это работает подробнее
При вызове метода в стеке выделяется кадр, при возврате из метода он разрушается. Стек живёт недолго и имеет фиксированный, обычно небольшой размер; его переполнение приводит к StackOverflowError.
Куча обычно значительно больше стека, её размер задаётся параметрами -Xmx и -Xms. Объект в куче живёт, пока на него есть ссылки, а освобождением памяти занимается сборщик мусора. Для работы GC куча делится на поколения: молодое (Eden и survivor-области) и старое.
- Если ссылка на объект — локальная переменная, сама ссылка лежит в стеке потока, а объект — в куче.
- В памяти JVM есть и другие области: Metaspace (метаданные классов и статические поля), PC Register и стек нативных методов.
Пример кода
public class HeapStackExample {
private int fieldValue = 10; // примитив-поле живёт в куче
public static void main(String[] args) {
int local = 42; // локальный примитив живёт в стеке
HeapStackExample obj = new HeapStackExample(); // объект в куче
System.out.println(local + obj.fieldValue); // 52
}
}Что использовать на практике
- Настраивайте размер кучи через -Xms/-Xmx, а размер стека потока — через -Xss.
- Держите локальные данные в методах: они автоматически освобождаются при выходе из кадра.
- Учитывайте поколения кучи: короткоживущие объекты должны умирать в молодом поколении, а не попадать в старое.
Подводные камни
- Глубокая рекурсия переполняет стек и даёт StackOverflowError, а не OutOfMemoryError.
- Куча общая для всех потоков, поэтому объекты доступны из разных потоков, и нужна синхронизация.
- Формулировка «примитивы всегда в стеке» неверна: примитивы-поля лежат в куче вместе с объектом.
Как отвечать на собеседовании
- Опишите стек: кадры методов, LIFO, локальные примитивы и ссылки → опишите кучу: объекты из new, общая для потоков, управляется GC → ответьте про примитивы (локальные в стеке, поля в куче) → добавьте Metaspace и другие области памяти → завершите параметрами JVM.