單個進程中最大線程數探索

【轉載自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。

相關文章
相關標籤/搜索