Netty4.1.6版本 記憶體洩漏問題以及解決方法
最近在專案中遇到一個問題,是關於Netty4.1.6版本,在日誌中列印以下錯誤訊息,
i.n.channel.DefaultChannelPipeline - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception. io.netty.util.internal.OutOfDirectMemoryError: failed to allocate 16777216 byte(s) of direct memory (used: 1023410176, max: 1029177344)
這個問題得出現,當時以為是JAVA虛擬機器記憶體洩漏,也沒有具體去找原因,覺得是記憶體空間不足,所以直接就採用-Xmx4096m .這樣配置方法,分配最大記憶體。好像程式沒到三天,生產環境又出問題,這就老火了,然後將其他專案暫停,慢慢下來分析。先是檢視記憶體,然後發現JAVA虛擬機器還好。慢慢定位,覺得是不是Netty得問題,然後網上搜尋,起始確實又很多人遇到過類似得問題,具體原因是Netty得回收機制和虛擬機器得垃圾回收策略不一樣,一個是採用計數得方法回收,這樣得話,netty框架中所用得記憶體沒有得到釋放,就會一直存在,但是,由於是長兩家,是平臺接入資料,幾乎資料一直都處於傳輸,從而,發現記憶體24小時間,一直沒有釋放一點記憶體,基本都是筆直得向上,直接到達分配最大記憶體。當出現這樣現象後,再再測試環境中,增加-Dio.netty.leakDetectionLevel=advanced 這個指令配置再環境中,列印netty哪些記憶體得不到釋放,通過這些日誌回得到問題得所在。
上圖中標紅色得地方,就是netty中,ByteBuf。這個是在netty4後,引進得,但是需要自己在釋放掉這個bytebuf,原因是一直處於連線中,一直分配得是directMemory,但是採用得是計數回收,沒有采用realse方法,則該bytebuf一直被分配,從沒被回收,最後則會造成directMemoryError錯誤。可以通過幾種方法一起,解決上述錯誤。
1.官網說得升級版本,在4.1.21以後,好像優化了byteBuf回收機制。
2.netty得channelRead 和channelWrite都需要判斷下,用isReadable 和iswriteable去判斷,看空間是否支援可寫和可讀。
3. ReferenceCountUtil.release(msg);在讀資料時候,在結束時候,需要釋放,將byteBuf回收到直接記憶體池中。
通過上述方法,應該可以解決directMemoryError問題,有些地方闡述得可能不夠好,或許是自己認識不對得地方請見諒,因為自己也是希望自己遇到得問題讓大家方便知道。