Runtime data areas
JVM делит память на области. Heap — общая для всех потоков, там живут все объекты и массивы. У каждого потока свои: JVM stack (кадры методов), program counter и, для нативных вызовов, native stack. Metaspace (вне кучи) хранит метаданные классов, code cache — скомпилированный JIT-код.
Heap собирается сборщиком мусора; стек освобождается автоматически при возврате из метода (LIFO). Переполнение стека — StackOverflowError (обычно глубокая рекурсия), нехватка кучи — OutOfMemoryError.

Стек против кучи
В кадре стека лежат примитивные локальные переменные и ссылки; сами объекты — всегда в куче. Поэтому Account a = new Account() кладёт ссылку в стек, а объект — в кучу.
JIT может через escape analysis доказать, что объект не «убегает» из метода, и применить scalar replacement — разложить его на локальные переменные и не аллоцировать в куче вовсе. Это, а не «маленькие объекты на стеке», и есть реальная оптимизация аллокаций.
void m() {
int x = 5; // примитив в кадре стека
Account a = new Account(); // ссылка в стеке, объект в куче
}
Устройство объекта в памяти
Объект в куче состоит из заголовка и полей. Заголовок — это mark word (хеш-код по требованию, биты блокировки/состояния GC, возраст для tenuring) и klass pointer (ссылка на метаданные класса в metaspace). У массивов в заголовке ещё длина.
Поля выравниваются, а весь объект дополняется до кратности 8 байт (padding) для эффективного доступа. Поэтому пустой объект занимает не ноль, а обычно 16 байт — это объясняет, почему миллионы крошечных объектов дороги по памяти.
Compressed oops
На 64-битной JVM ссылки (oops) по умолчанию сжимаются до 32 бит, пока куча меньше ~32 ГБ. Это вдвое уменьшает размер ссылок и заметно экономит память и нагрузку на кэш.
Практическое следствие: куча чуть выше 32 ГБ может вмещать меньше полезных данных, чем 31 ГБ, потому что отключаются compressed oops — частый сюрприз при тюнинге.
Metaspace
Метаданные классов с Java 8 живут в metaspace — нативной памяти вне кучи, которая растёт автоматически (в отличие от старого PermGen фиксированного размера). Это убрало классический «OutOfMemoryError: PermGen space».
Но утечки классов всё ещё возможны: например, постоянная перезагрузка классов через новые загрузчики (динамическая генерация, частый redeploy) раздувает metaspace — его ограничивают -XX:MaxMetaspaceSize.
Как отвечать на собеседовании
Назовите области (heap общий, стеки/PC по потоку, metaspace вне кучи), объясните «примитивы и ссылки в кадре, объекты в куче» и упомяните escape analysis вместо мифа «объекты на стеке». Бонус-уровень — заголовок объекта (mark word + klass pointer), padding до 8 байт и compressed oops с порогом ~32 ГБ.