Сколько стеков может быть в одном процессе
Что проверяют
Понимаете ли вы, что стек принадлежит потоку, а не процессу, и что общего у потоков внутри одной виртуальной машины. Заодно смотрят, знаете ли, чем ограничено число потоков и какая ошибка прилетает при исчерпании.
Как отвечать
Ровно столько, сколько потоков: у каждого свой стек. У потока платформы вдобавок есть нативный стек для вызовов через JNI и внутренних вызовов виртуальной машины. Общими остаются куча, метапространство и пул строк.
Что из этого следует на практике:
- размер стека задаётся флагом
-Xssи по умолчанию измеряется сотнями килобайт или мегабайтом, в зависимости от платформы. Эта память берётся не из кучи; - число потоков ограничивает не JVM, а операционная система и адресное пространство. При исчерпании падает
OutOfMemoryError: unable to create native thread, причём куча при этом может быть почти пустой; - переполнение одного стека это
StackOverflowError, обычно глубокая или бесконечная рекурсия. Другая ошибка и другая причина; - виртуальные потоки, ставшие стабильными в Java 21, держат стек в куче и умеют его сжимать, поэтому их спокойно бывает сотни тысяч.
Вывод, который и хотят услышать: потоки не бесплатны, под блокирующие задачи берут пул через ExecutorService, а не создают поток на каждый запрос.
Где спотыкаются
Отвечают «один», путая стек вызовов с кучей. После этого обычно не могут объяснить, почему локальные переменные разных потоков не мешают друг другу, а поля общего объекта мешают.
Считают, что больший -Xss лечит StackOverflowError. Иногда помогает при глубокой, но конечной рекурсии, чаще прячет отсутствие условия выхода, и при этом сокращает возможное число потоков: память умножается на всех.
Решают, что раз виртуальные потоки дешёвые, ими можно заменить пулы везде. Они выигрывают на ожидании ввода-вывода, на вычислениях упираются в те же ядра, а блокировка внутри synchronized способна закрепить виртуальный поток за несущим.