Короткий ответ
Стек создаётся для каждого потока отдельно и хранит кадры методов: локальные переменные, параметры и служебную информацию; работает по принципу 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.
- Держите локальные данные в методах: они автоматически освобождаются при выходе из кадра.