一、問題:
春節將至,系統訪問量進入高峰期。隨之系統出現了異常:java.lang.OutOfMemoryError: unable to create new native thread。在解決這個問題中,嘗試了各種方法,最后竟然是因為它......
二、解決辦法:
1、 關於這個問題,一開始猜想是因消息隊列(activemq)引起的,因為處理數據較多,開啟的線程數較多導致,因此對MQ搭建了集群。
MQ集群搭建方法:http://blog.csdn.net/jiangxuchen/article/details/8004561
但是搭建集群后發現,並沒有什么卵用,問題依舊。
繼續......
2、 接下來懷疑是系統里開的線程數太多,在優化后,問題仍然存在。
繼續......
3、 內存調優,減小xss值、JVM內存,仍然解決不了。
繼續......
4、 幾番周測,在整理思路后,決定首要任務就是如何重現該問題,於是編寫測試程序,測試出操作系統最大能夠創建的線程數:
1 import java.util.concurrent.CountDownLatch; 2 3 public class TestNativeOutOfMemoryError { 4 5 public static void main(String[] args) { 6 7 for (int i = 0;; i++) { 8 System.out.println("i = " + i); 9 new Thread(new HoldThread()).start(); 10 } 11 } 12 13 } 14 15 class HoldThread extends Thread { 16 CountDownLatch cdl = new CountDownLatch(1); 17 18 public HoldThread() { 19 this.setDaemon(true); 20 } 21 22 public void run() { 23 try { 24 cdl.await(); 25 } catch (InterruptedException e) { 26 } 27 } 28 }
運行后:
i = 982
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:597)
at TestNativeOutOfMemoryError.main(TestNativeOutOfMemoryError.java:20)
問題重現,在反復運行幾次后發現,生產系統最大只能創建980多個線程,生產系統操作系統64位centeros,jdk1.7,64G內存。而我本地PC電腦都可以創建2500左右。
感覺原因快找到了,切換到運行賬戶使用命令:
$ su Bst118
$ ulimit -u
$ 1024
生產上所有程序都是在Bst118賬戶下運行,於是查看該賬戶下所有的線程數總和為950,也即是說,隨時都可能會超過1024,導致內存溢出。查看看進程當前運行的線程數命令為:pstree -p 3660 | wc -l
原因找到,操作系統對運行程序的賬戶有最大線程數限制。
$ vim /etc/security/limits.d/90-nproc.conf
打開后發現除了root,其他賬戶都限制在1024個。
於是增加一條:Bst118 soft nproc 20000
為什么設置為20000,因為測試后發現,在運行到35000左右,系統就報內存溢出了,操作系統所有命令都不能使用,因此將程序最大線程數限制在20000。
修改后再沒出現內存溢出錯誤。問題解決。
三、思考
1、經過總結,在遇到問題后,不能盲目的到處修改,首先要做的就是重現問題,順藤摸瓜,逐步的找出根本原因。
2、關於tomcat內存調優,個人認為只有在中大型系統才需要調優或者服務器硬件條件一般的情況下才需要調優,才能有所效果。