Какой приблизительный размер стека по умолчанию в Java
Что проверяют
Понимаете ли вы, что стек в JVM свой у каждого потока, от чего зависит его размер и чем это оборачивается на практике. Следом почти всегда спрашивают про StackOverflowError и про то, сколько памяти съедят тысячи потоков.
Как отвечать
Точное число зависит от платформы и сборки JVM. У HotSpot на 64-битных Linux и macOS с x86_64 это 1 МБ на поток, на Windows тоже около 1 МБ, но значение берётся из заголовка исполняемого файла. На других архитектурах оно может отличаться, поэтому не гадайте, а проверяйте: java -XX:+PrintFlagsFinal -version | grep ThreadStackSize, число там в килобайтах.
Что ещё стоит сказать:
-Xss: задаёт размер стека новых платформенных потоков, например-Xss512kили-Xss2m. То же делает-XX:ThreadStackSize, только значение в килобайтах;- конструктор
Threadс параметромstackSize: размер для конкретного потока, но это лишь пожелание, JVM вправе его проигнорировать; - что лежит в стеке: фреймы вызовов, локальные примитивы и ссылки. Сами объекты живут в куче, поэтому
-Xssи-Xmxдруг с другом не связаны; - память: 1 МБ резервируется как виртуальная память, физические страницы выделяются по мере роста стека, так что тысяча потоков не займёт гигабайт RAM сразу;
- виртуальные потоки (Java 21): заранее выделенного стека у них нет, фреймы припаркованного потока хранятся в куче. Поэтому миллион таких потоков не требует миллиона стеков.
Глубина рекурсии при стеке в 1 МБ измеряется тысячами или десятками тысяч вызовов. Точнее не скажешь: всё зависит от размера фрейма и от того, скомпилировал ли метод JIT.
Где спотыкаются
Называют одно число как абсолютную истину, например «512 КБ», и не упоминают, что оно зависит от ОС, разрядности и настроек.
Лечат StackOverflowError увеличением -Xss. Если причина в бесконечной рекурсии, больший стек только отодвинет падение. Сначала смотрят трассу: повторяющийся фрагмент сразу показывает цикл вызовов, а законно глубокую рекурсию переписывают на итерацию с явным стеком в ArrayDeque.
Говорят, что объекты, созданные в методе, лежат в стеке. JIT может убрать выделение через escape-анализ, но по модели памяти Java объекты живут в куче.