去年升級過一個老的netty3的程式到netty4,近期突然註意到一個問題,就是這個程式隨著時間虛擬記憶體會不斷升高.之前升級的時候擔心存在記憶體泄露,所以還特意用jstate跟蹤過gc回收的情況,並沒有異常.雖然當時也發覺記憶體占用有緩慢升高的趨勢也沒有特別在意,僅做觀察處理. 由於同機器上還有另一個n
去年升級過一個老的netty3的程式到netty4,近期突然註意到一個問題,就是這個程式隨著時間虛擬記憶體會不斷升高.之前升級的時候擔心存在記憶體泄露,所以還特意用jstate跟蹤過gc回收的情況,並沒有異常.雖然當時也發覺記憶體占用有緩慢升高的趨勢也沒有特別在意,僅做觀察處理.
由於同機器上還有另一個netty3的老項目可以做對比,所以發覺還是有異常,同時啟動的程式虛擬記憶體占用是老項目的3倍,還沒有停止的趨勢.
決定還是排查一下,jstack 進程號 > 文件名 ,將堆棧信息dump出一份,觀察堆棧信息發現:
"defaultEventExecutorGroup-5-2" prio=10 tid=0x0000000044191000 nid=0x1df0 waiting on condition [0x0000000043ada000]
java.lang.Thread.State: WAITING (parking)
存在大量以上信息.其中defaultEventExecutorGroup-5-2信息中5為線程組的id,2為線程組中的線程id.然後發現一個特點就是日誌中有大量的不同線程組的defaultEventExecutorGroup出現.馬上想到一種可能.翻看原始代碼中defaultEventExecutorGroup的創建地點:
protected void initChannel(SocketChannel ch) throws Exception { ......
EventExecutorGroup excutor = new DefaultEventExecutorGroup(16); channelHandler = getMessageConnectorHandler(); p.addLast(excutor,"messageConnectorHandler", channelHandler); }
果然當時犯糊塗了,當時想著反正spring是單例,這種初始化方法也就調用一次,局部變數new出來也沒什麼..但是忘了一件重要的事情就是,這個方法所在的類根本就不是註入的,而是直接new出來的.所以這個局部的DefaultEventExecutorGroup對象每次都是重新創建,導致出現不同線程組的多個線程池出現.
將此線程池提升到靜態的成員變數後問題解決:
private final static EventExecutorGroup excutor = new DefaultEventExecutorGroup(16);