天天看點

使用Mina出現的JNI OutOfMemory的解決方法

最新在使用MINA作了UDP伺服器和UDP用戶端,在最後性能測試時,總是遇到OutOfMemory的問題,很是郁悶,定位了三天,後來終于找到了解決方法。和大家分享一下,以免大家再走同樣的彎路。

我們性能測試場景如下:

Client起100個線程同時向Server發UDP消息,Server接收到請求後立即向Client回響應;

在前10秒内,伺服器響應特别快,大概每秒可以達到4000個消息,但到了10多秒後,伺服器的響應就越來越慢,後來基本上就不響應,又或者直接OutOfMemory,并出現下面的錯:

request <size> bytes for <reason>. Out of swap space?

一開始我們一直以為是緩存中的對象未清理掉而導緻的問題,定位了一段時間後,發現緩存中的内容已經及時清理了。打開GC日志,也沒有發現問題。

後來,我們就開始上網狂找資料,發現原來Java記憶體分為兩種,Heap記憶體和JVM使用的記憶體,

Heap記憶體就是一般的JAVA對象使用記憶體;

JVM使用的記憶體,就是指JVM在運作過程中要使用的記憶體,JVM最終要通過調用JNI,本地方法運作也是需要記憶體的,這部分記憶體JVM直接向OS申請。

既然我們自己的代碼中使用的JAVA對象已經及時清理,那是不是JNI記憶體洩漏了?可是我們的代碼,基本上沒有使用JNI啊。難道是MINA的問題?大概看了下MINA的源碼,MINA是使用Java的NIO包下的類來實作的,打開Java的-verbose:jni選項,可以看出,NIO中的類很多都是通過JNI來實作的。

好了,繼續定位,發現我們的代碼中,大量使用了MINA提供的IoBuffer類,MINA為我們構造了大量的IoBuffer對象,我們自己也構造了大量的IoBuffer對象,會不會這個類的對象沒有及時清理?

帶着疑問,我看了IoBuffer的所有方法,其中有個free()方法,看了注釋,是用來清理記憶體的。

于是嘗試在所有使用完IoBuffer的代碼處都加上了調用free()方法的代碼,再進行測試,終于OK了。

UDP伺服器穩定運作後,記憶體最大隻使用了200多M,問題搞定。

所有使用Java的NIO包下的類,最好都多注意下JDK文檔,看是否需要主動調用某方法來釋放内容。