1. Обзор
С годами производительность систем, которые мы используем, увеличилась в геометрической прогрессии. Следовательно, количество потоков, которые поддерживает виртуальная машина Java, также увеличилось.
Но сколько мы на самом деле можем создать? Ответ не является точным числом, потому что оно зависит от множества факторов.
Мы обсудим пару этих факторов и то, как они влияют на количество потоков, которые мы можем создать в виртуальной машине Java.
2. Память стека
Одним из наиболее важных компонентов потока является его стек. Максимальный размер стека и количество создаваемых потоков напрямую зависят от объема доступной системной памяти.
Таким образом, увеличение объема памяти также увеличивает максимальное количество потоков, которые мы можем запустить в системе. Подробнее о размере стека можно прочитать в нашей статье Настройка размеров стека в JVM .
Наконец, стоит упомянуть, что, начиная с Java 11, JVM не выделяет агрессивно всю зарезервированную память для стека. Это помогает увеличить количество потоков, которые мы можем запустить. Другими словами, даже если мы увеличим максимальный размер стека, объем памяти, используемый потоком, будет зависеть от фактического размера стека.
3. Куча памяти
Куча не влияет напрямую на количество потоков, которые мы можем выполнить. Но он также использует ту же системную память.
Таким образом, увеличение размера кучи ограничивает доступную память для стека , тем самым уменьшая максимальное количество потоков, которые мы можем создать.
4. Выбор операционной системы
При создании нового потока Java создается новый собственный поток ОС, напрямую связанный с потоком из виртуальной машины.
Следовательно, операционная система контролирует управление потоком.
Кроме того, могут применяться различные ограничения в зависимости от типа операционной системы.
В следующих подразделах мы рассмотрим эти аспекты для наиболее распространенных систем.
4.1. линукс
Системы на базе Linux на уровне ядра рассматривают потоки как процессы. Таким образом, ограничения процесса, такие как параметр ядра pid_max
, будут напрямую влиять на количество потоков, которые мы можем создать.
Другой параметр ядра — threads-max
, который описывает общее максимальное количество потоков.
Мы можем получить все эти параметры, выполнив sysctl kernel.<parameter-name>
.
Наконец, есть ограничение на максимальное количество процессов на пользователя, которое можно получить с помощью команды ulimit -u
.
4.2. Окна
На компьютерах с Windows для потоков не указано ограничение. Таким образом, мы можем создать столько потоков, сколько захотим, пока в нашей системе не закончится доступная системная память.
4.3. macOS
Есть два основных ограничения на системы, работающие под управлением macOS, определяемые двумя параметрами ядра:
num_threads
представляет общее максимальное количество потоков, которые могут быть созданы.num_taskthreads
представляет максимальное количество потоков на процесс
Доступ к значениям этих параметров можно получить, выполнив sysctl kern.
<имя-параметра>.
Стоит отметить, что при достижении одного из этих пределов будет выдана ошибка OutOfMemoryError
, что может ввести в заблуждение.
5. Виртуальные потоки
Мы можем еще больше увеличить количество потоков, которые мы можем создать, используя облегченные виртуальные потоки, поставляемые с Project Loom , которые еще не являются общедоступными.
Виртуальные потоки создаются JVM и не используют потоки ОС , а это значит, что мы можем буквально создавать их миллионы одновременно.
6. Заключение
В этой статье мы рассмотрели наиболее важные аспекты, которые могут повлиять на максимальное количество потоков, которые можно создать в виртуальной машине Java.
Однако в большинстве случаев увеличение лимита вряд ли навсегда решит проблемы масштабируемости. Нам нужно будет переосмыслить реализацию приложения или даже применить горизонтальное масштабирование.