JVM 可开辟线程数量受什么影响

首先要说明一点,Java线程的实现是基于底层系统的线程机制来实现的,程序中开的线程并不全部取决于JVM虚拟机栈,而是取决于CPU,操作系统,其他进程,Java的版本。JVM的线程与计算机本身性能相关。

以前写过一个例子,统计可以开辟的线程数量,通过不断的申请Thread,最终会报错,输出一个当前开辟线程的数量:

public class ThreadCount{
    private static Object obj = new Object();
    private static int count = 0;
    public static void main(String[] args){
        for(;;){
            new Thread(new Runnable(){
                    public void run(){
                        synchronized(obj){
                            count += 1;
                            System.out.println("Thread #"+count);
                        }
                        for(;;){
                            try {
                                Thread.sleep(1000);
                            } catch (Exception e){
                                System.err.println(e);
                            }
                        }
                    }
                }).start();
        }
    }
}

运行结果上传图片有点问题,结果就不贴了,每个人的机器,结果都是不同的,可以运行下。

 

既然线程数量于计算机本身相关,我们是不是不可调控,是固定的呢?

答案显然不是的,在不考虑系统本身限制的情况下,主要跟JVM一下几点有关:

  • -Xms 初始堆大小 (在实际生产中,一般把-Xms和-Xmx设置成一样的。)
  • -Xmx 最大堆大小
  • -Xss 每个线程栈大小

结论1:当给JVM的堆内存分配的越大,系统可创建的线程数量就越少(可以通过上面测试程序,不断的改变-Xmx,-Xms的值,观看最后异常时的线程数量)。这个如何理解呢?很简单,因为线程占用的是系统空间,所以当JVM的堆内存越大,系统本身的内存就越少,自然可生成的线程数量就越少。

结论2:当-Xss的的值越小,可生成的线程数量就越多。(一样可以通过上面测试,保持-Xmx,-Xms不变,改变-Xss的值,jdk5以下默认好像是256K,以上默认为1M,具体记不太清楚了)。这个理解也很简单,线程可用空间保持不变,每个线程占用的栈内存大小变小,自然可生成的线程数量就越多。

 

那么是不是不断加大可用内存,线程数量也会不断增长呢?

这个当然不是,上面我特意加粗了不考虑系统本省限制的情况,所以说线程数量还与系统限制有关。主要跟一下几个参数有关(Linux下的):

  • /proc/sys/kernel/pid_max 增大,线程数量增大,pid_max有最高值,超过之后不再改变,而且32,64位也不一样
  • /proc/sys/kernel/thread-max 系统可以生成最大线程数量
  • max_user_process(ulimit -u)centos系统上才有,没有具体研究
  • /proc/sys/vm/max_map_count 增大,数量增多

 

总结:线程最大数量由JVM的堆(-Xmx,-Xms)大小、Thread的栈(-Xss)内存大小、系统最大可创建的线程数的限制参数三个方面影响。不考虑系统限制,可以通过这个公式估算:

线程数量 = (机器本身可用内存 - JVM分配的堆内存) / Xss的值。

上一篇:20200730 尚硅谷 JVM 11 - 直接内存


下一篇:什么是Java / JVM中的-Xms和-Xms参数(已更新至Java 13)