Linux中每个进程的最大线程数是多少?

302

在Linux下,一个进程能够创建的最大线程数是多少?

如果有可能的话,如何修改这个值?

18个回答

299

Linux没有单独的进程线程限制,只有一个系统上总进程数的限制(在Linux中,线程本质上就是共享地址空间的进程),您可以像这样查看:

cat /proc/sys/kernel/threads-max

默认值为内存页数/4。您可以像这样增加它:

echo 100000 > /proc/sys/kernel/threads-max

对于单个用户可以创建的进程数(包括线程数),也存在限制,请参阅ulimit/getrlimit了解这些限制的详细信息。


4
如果/proc/sys/vm/max_map_count的限制太低,可能会限制线程数量。如果遇到这种情况,增加该限制的值很安全。 - Mikko Rantalainen
1
Robert:Linux 间接实现了每个进程的限制。请查看我的回答以获取详细信息 ;) - codersofthedark
我正在尝试在我的Ubuntu 12.04上更改这个,但您的命令没有更改它。我还尝试使用vi进行更改,但是当我尝试在vi上保存时,我会收到“E667:Fsync失败”的错误提示。 - Siddharth
4
最大线程数是根据总内存计算的,而不是虚拟内存。 - c4f4t0r
2
每个线程的堆栈大小(在您的系统上默认值)很可能是限制因素,而不是其他任何因素。减少每个线程的堆栈大小是增加总线程数的一种方法(尽管这通常不是一个好主意)。 - Randy Howard

74

错误的说法是Linux没有进程线程限制。

Linux间接实现了每个进程的最大线程数限制!!

number of threads = total virtual memory / (stack size*1024*1024)

因此,可以通过增加总虚拟内存或减少堆栈大小来增加每个进程的线程数。但是,太大幅度地缩小堆栈大小可能会导致堆栈溢出而导致代码失败,而最大虚拟内存等于交换空间。

检查您的机器:

总虚拟内存:ulimit -v(默认为无限制,因此需要增加交换空间以增加此值)

总堆栈大小:ulimit -s(默认为8Mb)

增加这些值的命令:

ulimit -s newvalue

ulimit -v newvalue

*用要作为限制的新值替换原有值。

参考资料:

http://dustycodes.wordpress.com/2012/02/09/increasing-number-of-threads-per-process/


13
除了三个小细节:1. Linux不能做到这一点,栈的存在和内存与地址空间的有限大小无关。2. 创建线程时必须指定线程的堆栈,这与“ulimit -s”无关。很有可能(不明智,但可能)创建与可能的线程ID数量相同的线程。在64位Linux下,甚至可以轻松地“可能”创建比线程ID更多的线程(当然不可能,但就栈而言,是可能的)。3. 堆栈保留、提交和虚拟内存是不同的概念,特别是在OC方面。 - Damon
是的,要增加线程数,您需要增加虚拟内存或减小堆栈大小。在树莓派上,我没有找到增加虚拟内存的方法,如果将堆栈大小从默认的8MB减小到1MB,则可能每个进程可以获得超过1000个线程,但使用“ulimit -s”命令减小堆栈大小会影响所有线程。因此,我的解决方案是使用“pthread_t”实例的“线程类”,因为pthread_t让我可以为每个线程设置堆栈大小。最终,在树莓派上,我可以实现每个进程超过1000个线程,每个线程都有1MB的堆栈。 - Deulis

45

在实际应用中,线程数量的限制通常由堆栈空间决定。如果每个线程分配1MB的堆栈空间(我不确定这是否是Linux上的默认值),那么在32位系统上,如果最后1GB保留给内核,那么大约在创建3000个线程后就会耗尽地址空间。

然而,如果你使用超过几十个线程,你很可能会遇到糟糕的性能问题。迟早会出现过多的上下文切换开销、调度器负担等问题。(创建大量的线程除了占用大量内存外并没有太多作用。但是大量有实际工作任务的线程将争夺可用的CPU时间导致效率下降)

在什么情况下需要考虑线程数量的限制?


6
每个线程的堆栈1MB太高了,很多程序并不需要这么多的堆栈空间。性能将取决于可运行进程的数量,而不是存在的线程数量。我现在有一台机器正在运行,有1200多个线程,负载为0.40。 - Robert Gamble
19
性能取决于线程在做什么。如果它们没有做很多事情,因此上限可以比几十个更高,从而减少上下文切换。 - Corey Goldberg
堆栈正在动态增长,只有初始页面被分配。 - Michael Pankov
2
因为“超过几十个线程”的原因而被踩,要么增加它,要么删除它,要么提供支持来源。 - dreua

38

在 Linux 上正确地使用 100k 线程:

ulimit -s  256
ulimit -i  120000
echo 120000 > /proc/sys/kernel/threads-max
echo 600000 > /proc/sys/vm/max_map_count
echo 200000 > /proc/sys/kernel/pid_max 

 ./100k-pthread-create-app

2018 年 Thomas 的更新,针对 systemd 系统:

/etc/systemd/logind.conf: UserTasksMax=100000

4
谢谢,这终于让我突破了32,000个Java线程计数。 - berezovskyi
1
对我不起作用:$ ulimit -s 100000 $ ulimit -i 63645 $ cat /proc/sys/kernel/threads-max 127626 $ cat /proc/sys/vm/max_map_count 600000 $ cat /proc/sys/kernel/pid_max 200000 $ java -Xmx4G -Xss256k -cp . ThreadCreation ... 11542 11543 java.lang.OutOfMemoryError: 无法创建新的本机线程 at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:717) at ThreadCreation.main(ThreadCreation.java:15) - Martin Vysny
@MartinVysny ulimit -s = 线程大小(以KB为单位)。因此,您正在尝试创建具有100MB线程堆栈大小的线程。 - Vladimir Kunschikov
没有检查就添加了你的建议,@Thomas,无论如何感谢你的反馈。 - Vladimir Kunschikov
2
@VladimirKunschikov 谢谢伙计,你的解决方案真的很有效,还有感谢Thomas添加了那一行额外的代码,我可以确认如果没有那一行代码是行不通的。 - Bill Hoo

17

Linux不使用虚拟内存计算线程的最大值,而是使用系统中安装的物理RAM。

 max_threads = totalram_pages / (8 * 8192 / 4096);

http://kavassalis.com/2011/03/linux-and-the-maximum-number-of-processes-threads/

kernel/fork.c

/* The default maximum number of threads is set to a safe
 * value: the thread structures can take up at most half
 * of memory.
 */
max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE);

每个系统的线程最大值都不同,因为安装的内存大小可能不同。我知道Linux不需要增加虚拟内存,因为在32位上,我们有3 GB的用户空间和1 GB的内核空间,在64位上,我们有128 TB的虚拟内存,这在Solaris上发生。如果要增加虚拟内存,则需要添加交换空间。


14

要检索它:

cat /proc/sys/kernel/threads-max

设置方法如下:

echo 123456789 | sudo tee -a /proc/sys/kernel/threads-max

123456789 = 线程数


尝试使用root权限进行写入时,我仍然遇到了权限被拒绝的问题。 - Kim
嗯,这篇文章发布已经快十年了。我对当前的情况不是很了解,但很多事情可能已经发生了改变(而且很可能已经发生了)。 - Vincent Van Den Berghe
1
使用perm-deny时可能会出现问题,可能会丢失sudo操作符(>)部分:尝试 echo 12345678 | sudo tee -a /proc/sys/kernel/threads-max - dwanderson

10

线程数限制:

$ cat /proc/sys/kernel/threads-max 

计算方法:

max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE);

并且: x86_64页面大小(PAGE_SIZE)为4K; 像所有其他架构一样,x86_64为每个活动线程提供内核栈。这些线程栈的大小为THREAD_SIZE(2*PAGE_SIZE);

对于mempages:

cat /proc/zoneinfo | grep spanned | awk '{totalpages=totalpages+$2} END {print totalpages}';

实际上,线程内存堆栈大小的限制与线程数无关 (ulimit -s).

P.S:我的 RHEL 虚拟机中线程内存堆栈限制为 10M,在 1.5G 内存的情况下,这个虚拟机只能支持 150 个线程?


我有一台11 GB RAM的Ubuntu 64位虚拟机。我的VM上的threads-max为95377。但是,根据您提供的公式,max_threads为204800。为什么会不匹配?请澄清。根据上面给出的公式,mempages为3276799。 - Mohan

6

现在,对于任何查看此内容的人,在systemd系统上(在我的情况下,特别是Ubuntu 16.04),cgroup pids.max参数强制执行另一个限制。

默认情况下,它设置为12,288,并且可以在/etc/systemd/logind.conf中覆盖。

其他建议仍然适用,包括pids_max、threads-max、max_maps_count、ulimits等。


5

使用 ulimit 命令检查每个线程的堆栈大小,在我的情况下是 Redhat Linux 2.6:

    ulimit -a
...
    stack size              (kbytes, -s) 10240

每个线程都会被分配这么多内存(10MB)用于它的堆栈。由于32位程序最大地址空间为4GB,因此最多只能有4096MB / 10MB = 409个线程!!!减去程序代码、减去堆空间,可能导致观察到的最大线程数为300个。
您可以通过编译和在64位上运行,或者设置ulimit -s 8192甚至ulimit -s 4096来提高它。但这是否明智是另外一回事...

4

这可能并不重要。如果您的算法使用固定数量的线程(例如,如果您有4个或8个处理器,则使用4个或8个线程),则性能会更好。您可以使用工作队列、异步IO或类似libevent的东西来实现这一点。


4
多线程的目的不仅仅是提高性能。例如,在4核处理器上使用阻塞系统监听10个端口,这种情况下4核就没有意义了。 - obayhan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接