Java线程在64位Linux上的堆栈大小

4

我的目标是确定最大线程数,以便可以并行运行。我通过谷歌搜索了很多相关链接,其中他们给出了简单的数学计算方法:除以RAM / StackSize。在64位Linux中,我们将线程堆栈大小定义为10 MB(ulimit -s = 10240kb),而RAM为4GB,留下1 GB用于操作系统。按照这个计算方法,我可以拥有大约300个左右的线程,但我编写的小型测试应用程序却可以达到 ~32297 线程,然后会提示内存不足错误。

我尝试了不同的-Xss值,但是这些值对线程计数几乎没有任何影响,它仍保持在 ~32297。这让我留下了一个印象,即堆栈大小是可变的,并且由操作系统决定,在需要时可以增加到我们定义的最大值,但是无论我在哪里阅读,都说堆栈大小是静态的。

我到底缺少了什么?


1
你可能会受到内核的限制,就像这里所提到的那样。 - Joachim Sauer
3
您可以使用与处理器或核心数量相同的线程来实现真正的并行运行。否则,JVM 调度程序会有自己的方式来交错它们。 - dimitrisli
@Joachim:我看到了这篇文章,谢谢。您能否建议一下线程最大变量(值为81920)和堆栈大小(10 MB)以及4 GB的内存背后的决定性因素是什么?我无法计算出这些数字。 - Gaurav
通过遵循所有这些检查,我解决了这个问题。 - javaPhobic
5个回答

5

尝试使用以下命令来检查/更改Linux的最大堆栈大小:

ulimit -s

还需要检查Linux线程限制。

cat /proc/sys/kernel/threads-max  

1
cat /proc/sys/kernel/threads-max 是 81920。我想知道 ulimit -s 和 threads-max 之间的关系,如果我更改堆栈大小,threads-max 值会更新吗? - Gaurav

3

在你分享的链接中,他们提到在64位下,堆栈大小为128K时,限制为32,072;而堆栈大小为512K时,限制仍然是32,072。你知道为什么堆栈大小不会对可创建的线程数产生任何影响吗? - Gaurav

3
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/


"ulimit -v" 显示默认值为 "无限制"。但是,在我的 12 GB RAM Ubuntu VM 上,系统将内核参数 threads-max 计算为 95k。请澄清即使 "ulimit -v" 显示 "无限制",threads-max 是如何计算的? - Mohan
由于我们正在乘以1024 * 1024,我假设虚拟内存应该以GB为单位给出。请确认。 - Mohan

0

这是因为 pid_max 内核变量默认为 32768,但对于 64 位系统可以增加到 400 万。 解释很简单,1 线程 = 1 进程,将有 1 个 PID(进程 ID),因此没有更多的 PID,也没有更多的线程。


0

你所读到的只适用于32位架构,当限制是地址空间(2^32)时。你实际上有这样的东西:Xmx + MaxPermSize +(Xss *线程数)<操作系统允许用户进程的最大地址空间。根据操作系统和物理硬件,你可能会得到像你说的那样的3GB。但这与RAM无关。

对于64位架构,你的地址空间不会是限制(2^64)。你应该看看操作系统的限制,就像有人之前说过的那样。


好的,仍未回答的问题是为什么即使将堆栈大小更改为非常大或非常小的值,最大线程计数仍保持不变。操作系统是否动态选择堆栈大小? - Gaurav

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