最近用java開發了一個應用,主要是使用java中的Timer類做定時操作網頁的事情。程序的設計是每個用戶可能會有至少8個Timer類,這樣當用戶數多時Timer的數量就呈直線上升了。按照java的官方文檔說明,Timer類會自動啟動一個新線程,而多個Timer類則會有開辟多個線程,同時Timer類的線程是非daemon(守護)線程,所以一旦啟動除非明確cancel掉,是一直存在的。因此,我的這個應用當用戶數多了之後,大概100個用戶,初步估算有近800個線程,在768M內存的服務器上運行一段時間後內存就飙升至96%多,最後系統響應非常慢,導致宕機。
Java 8 中 HashMap 的性能提升 http://www.linuxidc.com/Linux/2014-04/100868.htm
Java 8 的 Nashorn 引擎 http://www.linuxidc.com/Linux/2014-03/98880.htm
Java 8簡明教程 http://www.linuxidc.com/Linux/2014-03/98754.htm
剛開始不太清楚是怎麼回事,後來做了個實驗,在2G內存的VPS上快速new一萬個Timer來,結果5000多個左右的時就報內存溢出,top查看內存為0,同時顯示錯誤,無法創建native thread的錯誤。後來仔細想想,每個線程也有自己的堆棧,需要消耗內存的,因此當Timer類多的時候內存占用就會直線上升也就不足為奇了。因此在程序中使用線程也是要當心的,雖然線程是個好東西。更多的情況下要考慮線程的復用,比如使用java的線程池時情況就會有天壤之別,同樣在這個VPS,我用一個Timer類,快速提交10000個TimerTask,結果內存占用非常小,幾乎沒有太大的變化,雖然這裡只用到了一個線程,可見線程的作用和厲害。
找到了原因,那就是調校優化程序了,要不一個應用幾百個用戶都撐不住那就掉大了,呵呵。