Что хранится в стеке и в куче в Java
Что проверяют
Понимаете ли вы модель памяти JVM на уровне «где живёт это значение и кто его освобождает», а не как заученную пару «примитивы в стеке, объекты в куче». Следом почти всегда спрашивают, где хранится поле int внутри объекта, или просят сравнить StackOverflowError и OutOfMemoryError.
Как отвечать
Начните с того, что стек у каждого потока свой, а куча общая для всех потоков:
- стек потока: состоит из фреймов, по одному на вызов метода. Во фрейме лежат локальные переменные, параметры и промежуточные значения. Для примитивов это само значение, для объектов только ссылка. Фрейм исчезает при выходе из метода, сборщик мусора тут не участвует;
- куча: все объекты и массивы, созданные через
new, включаяint[]и примитивные поля объектов. Строковый пул тоже в куче (с Java 7), статические поля в современных HotSpot хранятся при объектеClass, то есть тоже в куче; - Metaspace: метаданные классов в нативной памяти, заменил PermGen в Java 8.
Размеры задаются флагами: -Xss для стека потока, -Xms и -Xmx для кучи. Переполнение стека даёт StackOverflowError, обычно от слишком глубокой рекурсии; нехватка кучи даёт OutOfMemoryError: Java heap space.
Сильный ответ добавляет две оговорки. Первая: JIT с помощью escape analysis может вообще не создавать объект, который не покидает метод, разложив его на отдельные поля (scalar replacement). Вторая: у виртуальных потоков из Java 21 стек при отмонтировании копируется в кучу, поэтому миллион таких потоков помещается в память.
Где спотыкаются
Говорят «примитивы всегда в стеке». Поле int age у объекта User лежит в куче вместе с объектом, в стеке только локальные переменные.
Утверждают, что кучу нужно освобождать явно. В Java этим занимается GC, а утечка памяти выглядит иначе: объект остаётся достижимым, например лежит в статической коллекции или в кеше без вытеснения.
Путают передачу аргументов. Java всегда передаёт по значению, просто для объекта значением является ссылка: переприсвоить параметр так, чтобы это увидел вызывающий код, нельзя, а изменить поля объекта можно.