什么是 JVM 可以创建的线程的阈值限制数

What is threshold limit number of threads that a JVM can create

编辑:

正如@Petesh 所说,我达到了 kern.num_taskthreads 限制而不是总线程限制,这限制了单个进程的线程数。

sysctl kern.num_taskthreads是:

kern.num_taskthreads: 2048

当我使用 VM args -XX:ThreadStackSize=1g 时,我只能创建 122 个线程;创建了 -XX:ThreadStackSize=2g58 个线程。有道理。

但仍然是 st运行ge,无论我如何更改 -Xss 参数,结果始终是 2031-Xss args 似乎只适用于我现在不确定的主线程。

原题:

我运行 测试一个JVM 可以创建多少个线程。当我调整 JVM args -Xmx-Xss 时,结果没有改变。

代码如下:

public class ThreadTest {
    public static void main(String[] args) {
        int count = 0;
        try {
            while (true) {
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            TimeUnit.SECONDS.sleep(360);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
                thread.start();
                System.out.println(count);
            }

        } catch (Error e) {
            e.printStackTrace();
        }
    }
}

以及 OS 信息:

  • Model Name: MacBook Pro
  • Model Identifier: MacBookPro11,4
  • Processor Name: Intel Core i7
  • Processor Speed: 2.2 GHz
  • Number of Processors: 1
  • Total Number of Cores: 4
  • L2 Cache (per Core): 256 KB
  • L3 Cache: 6 MB
  • Memory: 16 GB

java版本:

➤ java -version                                                                                                                                                          
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Dynamic Code Evolution 64-Bit Server VM (build 25.71-b01-dcevmlight-1, mixed mode)

结果:

ulimit -a

sysctl kern.num_threads:

kern.num_threads: 10240

我在我的linux jvm 1.8.0_92上测试了一下,和你说的一样,我发现:

Oracle 页面:

http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

它说:

以下示例将线程堆栈大小设置为不同单位的 1024 KB:

   -Xss1m
   -Xss1024k
   -Xss1048576

This option is equivalent to -XX:ThreadStackSize

所有这些东西都是 OS 特定的 - 在 OSX 的情况下,你有一个不能超过 sysctl kern.num_taskthreads 的每进程线程限制.您创建的线程数限制和 VM 创建线程的开销似乎表明您已达到该限制。

-XX:ThreadStackSize-Xss<size> 之间的区别有点奇怪。在这种情况下,我的分析基于 OSX oracle java 虚拟机(您表示您是 运行 不同的虚拟机)。

-Xss 将堆栈大小设置为 该字节数 。存储它的变量将它除以 1024。但是由于它计算它的方式,该值最终成为一个无意义的值(64 位 jvm,检查 linux 和 osx)——这是一些非常糟糕的溢出数学:

for i in {1..8}; do echo "${i}G:"; java -Xss${i}g -XX:+PrintFlagsFinal -version 2>&1 | grep ' ThreadStack'; done
1G:
     intx ThreadStackSize                          := 1048576                             {pd product}
2G:
     intx ThreadStackSize                          := 18014398507384832                    {pd product}
3G:
     intx ThreadStackSize                          := 18014398508433408                    {pd product}
4G:
     intx ThreadStackSize                          := 0                                   {pd product}
5G:
     intx ThreadStackSize                          := 1048576                             {pd product}
6G:
     intx ThreadStackSize                          := 18014398507384832                    {pd product}
7G:
     intx ThreadStackSize                          := 18014398508433408                    {pd product}
8G:
     intx ThreadStackSize                          := 0                                   {pd product}

当我们将其与 -XX:ThreadStackSize 进行比较时,我们得到了不同的画面:

首先,这些值按 1024 倍缩放 - 即所有请求的值实际上都是堆栈大小的 KB 数。

这意味着 -XX:ThreadstackSize 需要比 -Xss 的值低 1024 倍。事实上,您只能创建线程数的一小部分,并且进程的虚拟内存大小使这一点显而易见(取自进程的 vmmap 输出):

Stack                  0000000800004000-0000040800000000 [  4.0T] rw-/rwx SM=NUL  thread 23
Stack                  0000040800000000-0000040800003000 [   12K] rw-/rwx SM=PRV  thread 23

每个堆栈 4TB?那会很痛(这是你之前要求的):

一旦我们将其向下调整 1024 倍,我们将在第二个中获得相同数量的线程 运行 - 您可以在输出中更清楚地看到这些数字,并且它们与请求的线性比例尺码:

for i in {1..8}; do echo "${i}G:"; java -XX:ThreadStackSize=${i}m -XX:+PrintFlagsFinal -version 2>&1 | grep ' ThreadStack'; done
1G:
     intx ThreadStackSize                          := 1048576                             {pd product}
2G:
     intx ThreadStackSize                          := 2097152                             {pd product}
3G:
     intx ThreadStackSize                          := 3145728                             {pd product}
4G:
     intx ThreadStackSize                          := 4194304                             {pd product}
5G:
     intx ThreadStackSize                          := 5242880                             {pd product}
6G:
     intx ThreadStackSize                          := 6291456                             {pd product}
7G:
     intx ThreadStackSize                          := 7340032                             {pd product}
8G:
     intx ThreadStackSize                          := 8388608                             {pd product}

因此,看起来使用 -Xss<size> 确实只在您寻找小于 1GB 的堆栈大小时才有用;如果您正在寻找 > 1GB 的堆栈大小,那么您可以使用 -XX:ThreadStackSize.

明确指定它

找出溢出。 parses the Xss option:

的代码
julong long_ThreadStackSize = 0;
ArgsRange errcode = parse_memory_size(tail, &long_ThreadStackSize, 1000);

然后在恒星布偶表演中 it does:

FLAG_SET_CMDLINE(intx, ThreadStackSize,
                          round_to((int)long_ThreadStackSize, K) / K);

即将 long 向下转换为 int,然后传递给 round_to。这需要一个 Register 值,这是 64 位 VM 上的 64 位值。所以据我所知,你开始的价值是:

0x80000000

获取 sign extended 到:

0xFFFFFFFF80000000

除以 1024 (0x400):-

0x3FFFFFFFE00000 == 18,014,398,507,384,832

这样您就可以看到前面脚本中的 2GB 值是从哪里来的。

我记录了一个错误。源代码中需要的更改不是 (int)long_ThreadStackSize,应该是 (Register)long_ThreadStackSize 以保持计算正确。