1、問題起因
這個異常問題本質原因是我們創建了太多的線程,而能創建的線程數是有限制的,導致了異常的發生。能創建的線程數的具體計算公式如下:
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
- MaxProcessMemory 指的是一個進程的最大內存
- JVMMemory JVM內存
- ReservedOsMemory 保留的操作系統內存
- ThreadStackSize 線程棧的大小
在java語言裏, 當你創建一個線程的時候,虛擬機會在JVM內存創建一個Thread對象同時創建一個操作系統線程,而這個系統線程的內存用的不是JVMMemory,而是系統中剩下的內存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。
由公式得出結論:你給JVM內存越多,那麼你能創建的線程越少,越容易發生java.lang.OutOfMemoryError: unable to create new native thread。
2、解決問題
1、如果程序中有bug,導致創建大量不需要的線程或者線程沒有及時回收,那麼必須解決這個bug,修改參數是不能解決問題的。
2、如果程序確實需要大量的線程,現有的設置不能達到要求,那麼可以通過修改MaxProcessMemory,JVMMemory,ThreadStackSize這三個因素,來增加能創建的線程數:
MaxProcessMemory 使用64位操作系統
MaxProcessMemory進程最大的尋址空間,但我想這個值應該也不會超過虛擬內存和物理內存的總和吧。關於不同系統的進程可尋址的最大空間,可參考下面表格:
JVMMemory: Heap + PermGen
ReservedOSMemory:Native heap,JNI
在2000/XP/2003的boot.ini裏頭有一個啓動選項,好像是:/PAE /3G ,可以讓用戶進程最大內存擴充至3G,這時操作系統只能佔用最多1G的虛存。那樣應該可以讓JVM創建更多的線程。
JVMMemory 減少JVMMemory的分配 使用tomcat的catalina.bat這裏配置,下面有解析。
-Xms1024m
-Xmx1024m
-XX:PermSize=256M
-XX:MaxNewSize=512m
-XX:MaxPermSize=256m
-XX:SurvivorRatio=6
ThreadStackSize 減小單個線程的棧大小
-Xss(或-ss) 這個其實也是可以默認的,如果你真的覺得有設置的必要,你就改下吧,1.5以後是1M的默認大小(指一個線程的native空間),如果代碼不多,可以設置小點來讓系統可以接受更大的內存。注意,還有一個參數是-XX:ThreadStackSize,這兩個參數在設置的過程中如果都設置是有衝突的,一般按照JVM常理來說,誰設置在後面,就以誰爲主,但是最後發現如果是在1.6以上的版本,-Xss設置在後面的確都是以-Xss爲主,但是要是-XX:ThreadStackSize設置在後面,主線程還是爲-Xss爲主,而其它線程以-XX:ThreadStackSize爲主,主線程做了一個特殊判定處理;單獨設置都是以本身爲主,-Xss不設置也不會採用其默認值,除非兩個都不設置會採用-Xss的默認值。