測試在進行一次性能測試的時候發現併發300個請求時出現了下面的異常:java
HTTP Status 500 - Handler processing failed; nested exception is java.lang.OutOfMemoryError: unable to create new native threadajax
看到這個異常有點發慌,畢竟併發程序寫的少,忽然來這麼一個確實有點找不着背。但無論怎麼樣仍是先搜索一下是啥緣由吧。tomcat
這個錯誤是由於沒法再建立新線程致使的,緣由多是沒有更多的空間用於建立線程,還有一個公式用來計算:服務器
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads多線程
這其中各個參數的意思是:
MaxProcessMemory:進程最大尋址空間。
JVMMMEMORY:jvm的內存空間(堆+永久區)-Xmx大小 (應該是實際分配大小)
ReservedOsMemory:操做系統預留內存
ThreadStackSize:-Xss大小併發
懶得寫了,找一篇參考:https://my.oschina.net/xinxingegeya/blog/744462jvm
因而我查看一下liunx系統的參數狀況:工具
[root@RHEL63temp ~]# ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 63628 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 1024 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
其中的max user processes只有1024個,心想着這事情可能問題不在於建立的限制,而是爲何要建立這麼多線程?畢竟只有300個併發,tomcat最多也就300個線程用於處理請求吧?性能
因而想了想程序代碼的問題,仍是要從代碼上去查找緣由。因而臨時開始研究了一下JVisualVM這個監控工具,在服務器上作了作配置,反正網上有教程。由於我使用的是Tomcat,因此直接就監控Tomcat吧,在catalina.sh中增長一些參數:測試
JAVA_OPTS="-server -Xmx384m -Xms128m -XX:PermSize=128M -XX:MaxPermSize=256m" -Dcom.sun.management.jmxremote.port=9998 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.49.199"
這樣就可使用JVisualVM經過JMX方式監控了。鏈接上後再進行測試問題緣由找到了。
線程產生這麼大主要是兩塊:
一、tomcat的自己須要支持併發的線程
二、smack產生的大量線程,並且連續壓測會發現smack的線程出現不釋放的狀況
這裏的關鍵是smack的使用,由於系統實現了一個功能就是經過網頁發起ajax請求,而後在服務端模擬即時經過用戶發送消息。由於併發300個請求,致使每一個請求都要建立smack的鏈接,而smack是用於客戶端開發的庫,啓動後會建立3個左右的線程用於鏈接和處理服務器的通信。這就致使同時會產生300*3的線程,因此併發時會所線程建立數用滿。
既然問題緣由找到了,因此這裏的問題可能仍是smack的使用問題,畢竟smack是個客戶端庫,不太適合於這種服務端的場景。
解決方法是使用其餘方式代替smack發消息,這樣只須要建立少許的線程就能夠知足要求,並且處理速度大大提高。