单个进程中最大线程数探索

【转载自http://blog.csdn.net/yohoph/article/details/48372805】java

windows 操做系统中容许的最大线程数。linux

 

===========================================================================windows

默认状况下,一个线程的栈要预留1M的内存空间服务器

而一个进程中可用的内存空间只有2G,因此理论上一个进程中最多能够开2048个线程并发

可是内存固然不可能彻底拿来做线程的栈,因此实际数目要比这个值要小。app

你也能够经过链接时修改默认栈大小,将其改的比较小,这样就能够多开一些线程。less

如将默认栈的大小改为512K,这样理论上最多就能够开4096个线程。async

即便物理内存再大,一个进程中能够起的线程总要受到2GB这个内存空间的限制。ide

比方说你的机器装了64GB物理内存,但每一个进程的内存空间仍是4GB,其中用户态可用的仍是2GB。测试

若是是同一台机器内的话,能起多少线程也是受内存限制的。每一个线程对象都要站用非页面内存,而

非页面内存也是有限的,当非页面内存被耗尽时,也就没法建立线程了。

若是物理内存很是大,同一台机器内能够跑的线程数目的限制值会愈来愈大。

在Windows下写个程序,一个进程Fork出2000个左右线程就会异常退出了,为何?

这个问题的产生是由于windows32位系统,一个进程所能使用的最大虚拟内存为2G,而一个线程的

默认线程栈StackSize为1024K(1M),这样当线程数量逼近2000时,2000*1024K=2G(大约),

内存资源就至关于耗尽。

MSDN原文:

“The number of threads a process can create is limited by the available virtual memory.

 By default, every thread has one megabyte of stack space. Therefore, you can create

 at most 2,028 threads. If you reduce the default stack size, you can create more threads. However, your application will have better performance if you create one thread per

processor and build queues of requests for which the application maintains the context

information. A thread would process all requests in a queue before processing requests

in the next queue.”

 

如何突破2000个限制?

能够经过修改CreateThread参数来缩小线程栈StackSize,例如

 

  1. #define MAX_THREADS 50000   
  2.     DWORD WINAPI ThreadProc( LPVOID lpParam ){  
  3.         while(1){  
  4.             Sleep(100000);  
  5.         }  
  6.         return 0;  
  7.     }  
  8.     int main() {  
  9.         DWORD dwThreadId[MAX_THREADS];  
  10.         HANDLE hThread[MAX_THREADS];  
  11.         for(int i = 0; i < MAX_THREADS; ++i){  
  12.         hThread[i] = CreateThread(0, 64, ThreadProc, 0, STACK_SIZE_PARAM_IS_A_RESERVATION, &dwThreadId[i]);  
  13.             if(0 == hThread[i]){  
  14.                 DWORD e = GetLastError();  
  15.                 printf(“%d\r\n”,e);  
  16.                 break;  
  17.             }  
  18.         }  
  19.      ThreadProc(0);  
  20.    }  

 

Cpp代码 
  1. #define MAX_THREADS 50000  
  2.     DWORD WINAPI ThreadProc( LPVOID lpParam ){  
  3.         while(1){  
  4.             Sleep(100000);  
  5.         }  
  6.         return 0;  
  7.     }  
  8.     int main() {  
  9.         DWORD dwThreadId[MAX_THREADS];  
  10.         HANDLE hThread[MAX_THREADS];  
  11.         for(int i = 0; i < MAX_THREADS; ++i){  
  12.         hThread[i] = CreateThread(0, 64, ThreadProc, 0, STACK_SIZE_PARAM_IS_A_RESERVATION, &dwThreadId[i]);  
  13.             if(0 == hThread[i]){  
  14.                 DWORD e = GetLastError();  
  15.                 printf(“%d\r\n”,e);  
  16.                 break;  
  17.             }  
  18.         }  
  19.      ThreadProc(0);  
  20.    }  

 

 

 

服务器端程序设计

若是你的服务器端程序设计成:来一个client链接请求则建立一个线程,那么就会存在2000个限制(在

硬件内存和CPU个数必定的状况下)。建议以下:

The “one thread per client” model is well-known not to scale beyond a dozen clients

or so. If you‘re going to be handling more than that many clients simultaneously,

you should move to a model where instead of dedicating a thread to a client, you

 instead allocate an object. (Someday I’ll muse on the duality between threads and

 objects.) Windows provides I/O completion ports and a thread pool to help you

convert from a thread-based model to a work-item-based model.

1. Serve many clients with each thread, and use nonblocking I/O and level-triggered

readiness notification

2. Serve many clients with each thread, and use nonblocking I/O and readiness

change notification

3. Serve many clients with each server thread, and use asynchronous I/O

--------------------

附:Win32将低区的2GB留给进程使用, 高区的2GB则留给系统使用。

Linux将高位1GB留给内核,低位3GB留给进程

 

linux系统中容许的最大线程数

==========================================================================================

JVM中可生成的最大Thread数量

 

JVM中能够生成的最大数量由JVM的堆内存大小、Thread的Stack内存大小、系统最大

可建立的线程数量(Java线程的实现是基于底层系统的线程机制来实现的,Windows下_beginthreadex,Linux下pthread_create)三个方面影响。

 
最近想测试下Openfire下的最大并发数,须要开大量线程来模拟客户端。对于一个JVM实例到底能开多少
个线程一直心存疑惑,因此打算实际测试下,简单google了把,找到影响线程数量的因素有下面几个:

-Xms

intial Java heap size

-Xmx

maximum java heap size

-Xss

the stack size for each thread

系统限制

系统最大可开线程数

测试程序以下:
 
  1. import java.util.concurrent.atomic.AtomicInteger;   
  2. public class TestThread extends Thread {   
  3.     private static final AtomicInteger count = new AtomicInteger();   
  4.     public static void main(String[] args) {   
  5.         while (true)   
  6.             (new TestThread()).start();   
  7.     }   
  8.     @Override   
  9.     public void run() {   
  10.         System.out.println(count.incrementAndGet());   
  11.         while (true)   
  12.             try {   
  13.                 Thread.sleep(Integer.MAX_VALUE);   
  14.             } catch (InterruptedException e) {   
  15.                 break;   
  16.             }   
  17.     }   
  18. }   
Java代码 
  1. import java.util.concurrent.atomic.AtomicInteger;   
  2. public class TestThread extends Thread {   
  3.     private static final AtomicInteger count = new AtomicInteger();   
  4.     public static void main(String[] args) {   
  5.         while (true)   
  6.             (new TestThread()).start();   
  7.     }   
  8.     @Override   
  9.     public void run() {   
  10.         System.out.println(count.incrementAndGet());   
  11.         while (true)   
  12.             try {   
  13.                 Thread.sleep(Integer.MAX_VALUE);   
  14.             } catch (InterruptedException e) {   
  15.                 break;   
  16.             }   
  17.     }   
  18. }   

 

测试环境:

系统:Ubuntu 10.04 Linux Kernel 2.6 (32位)

内存:2G

JDK:1.7

 

测试结果:

◆ 不考虑系统限制

 

-Xms

-Xmx

-Xss

结果

1024m

1024m

1024k

1737

1024m

1024m

64k

26077

512m

512m

64k

31842

256m

256m

64k

31842

在建立的线程数量达到31842个时,系统中没法建立任何线程。

 

由上面的测试结果能够看出增大堆内存(-Xms,-Xmx)会减小可建立的线程数量,增大线程栈内存

(-Xss,32位系统中此参数值最小为60K)也会减小可建立的线程数量。

 

◆ 结合系统限制

线程数量31842的限制是是由系统能够生成的最大线程数量决定的:/proc/sys/kernel/threads-max,

可其默认值是32080。修改其值为10000:echo 10000 > /proc/sys/kernel/threads-max,

修改后的测试结果以下:

 

-Xms

-Xmx

-Xss

结果

256m

256m

64k

9761

这样的话,是否是意味着能够配置尽可能多的线程?再作修改:echo 1000000 > /proc/sys/kernel/threads-max,

 

修改后的测试结果以下:

-Xms

-Xmx

-Xss

结果

256m

256m

64k

32279

128m

128m

64k

32279

发现线程数量在达到32279之后,再也不增加。查了一下,32位Linux系统可建立的最大pid数是32678,

这个数值能够经过/proc/sys/kernel/pid_max来作修改(修改方法同threads-max),可是在32系

统下这个值只能改小,没法更大。在threads-max必定的状况下,修改pid_max对应的测试结果以下:

 

pid_max

-Xms

-Xmx

-Xss

结果

1000

128m

128m

64k

582

10000

128m

128m

64k

9507

 

在Windows上的状况应该相似,不过相比Linux,Windows上可建立的线程数量可能更少。基于线
程模型的服务器总要受限于这个线程数量的限制。

 

 

总结:

JVM中能够生成的最大数量由JVM的堆内存大小、Thread的Stack内存大小、系统最大可建立的线程数量

(Java线程的实现是基于底层系统的线程机制来实现的,Windows下_beginthreadex,Linux下

pthread_create)三个方面影响。具体数量能够根据Java进程能够访问的最大内存(32位系统上通常2G)、

堆内存、Thread的Stack内存来估算。

序:

 

      在64位Linux系统(CentOS 6, 3G内存)下测试,发现还有一个参数是会限制线程数量:

max user process(可经过ulimit –a查看,默认值1024,经过ulimit –u能够修改此值),

这个值在上面的32位Ubuntu测试环境下并没有限制。

将threads-max,pid_max,max user process,这三个参数值都修改为100000,-Xms,

-Xmx尽可能小(128m,64m),-Xss尽可能小(64位下最小104k,可取值128k)。事先预测在

这样的测试环境下,线程数量就只会受限于测试环境的内存大小(3G),但是实际的测试结果是

线程数量在达到32K(32768,建立的数量最多的时候大概是33000左右)左右时JVM是抛出警告:

Attempt to allocate stack guard pages failed,而后出现OutOfMemoryError没法建立本

地线程。查看内存后发现还有不少空闲,因此应该不是内存容量的缘由。Google此警告无果,

暂时不知什么缘由,有待进一步研究。

序2:今天无心中发现文章[7],立刻试了下,果真这个因素会影响线程建立数量,按文中描述把/proc/sys/vm/max_map_count的数量翻倍,从65536变为131072,建立的线程总数

量达到65000+,电脑基本要卡死(3G内存)… 简单查了下这个参数的做用,在[8]中的描述以下:

“This file contains the maximum number of memory map areas a process may have.

Memory map areas are used as a side-effect of calling malloc, directly by mmap and

 mprotect, and also when loading shared libraries.

While most applications need less than a thousand maps, certain programs,

particularly malloc debuggers, may consume lots of them, e.g., up to one or two

 maps per allocation.

The default value is 65536.”

 

OK,这个问题总算完满解决,最后总结下影响Java线程数量的因素:

Java虚拟机自己:-Xms,-Xmx,-Xss;

系统限制:

/proc/sys/kernel/pid_max,

/proc/sys/kernel/thread-max,

max_user_process(ulimit -u),

/proc/sys/vm/max_map_count。

相关文章
相关标签/搜索