天天看點

NIO DirectByteBuffer 記憶體洩露的測試

      寫NIO程式經常使用ByteBuffer來讀取或者寫入資料,那麼使用ByteBuffer.allocate(capability)還是使用ByteBuffer.allocteDirect(capability)來配置設定緩存了?第一種方式是配置設定JVM堆記憶體,屬于GC管轄範圍,由于需要拷貝是以速度相對較慢;第二種方式是配置設定OS本地記憶體,不屬于GC管轄範圍,由于不需要記憶體拷貝是以速度相對較快。

      我們肯定想選擇比較快的,但問題是直接記憶體不屬于GC管轄範圍,需要弄清楚這部分記憶體如何管理,否則造成記憶體洩露就麻煩了。本地記憶體在JAVA中有一個對應的包裝類DirectByteBuffer,該類屬于Java類,适當的時候會被GC回收,當它被回收前會調用本地方法把直接記憶體給釋放了,是以本地記憶體可以随DirectByteBuffer對象被回收而自動回收,貌似沒有問題;但如果不斷配置設定本地記憶體,堆記憶體很少使用,那麼JVM就不需要執行GC,DirectByteBuffer對象們就不會被回收,這時候堆記憶體充足,但本地記憶體可能已經使用光了,再次嘗試配置設定本地記憶體就會出現OutOfMemoryError,那程式就直接崩潰了。

      有沒有解決方案?自動釋放不靠譜,我們是否可以手動釋放本地記憶體,把握主動權?果然DirectByteBuffer持有一個Cleaner對象,該對象有一個clean()方法可用于釋放本地記憶體,是以需要的時候我們可以調用這個方法手動釋放本地記憶體。

測試用例1:設定JVM參數-Xmx100m,運作異常,因為如果沒設定-XX:MaxDirectMemorySize,則預設與-Xmx參數值相同,配置設定128M直接記憶體超出限制範圍。

測試用例2:設定JVM參數-Xmx256m,運作正常,因為128M小于256M,屬于範圍内配置設定。

測試用例3:設定JVM參數-Xmx256m -XX:MaxDirectMemorySize=100M,運作異常,配置設定的直接記憶體128M超過限定的100M。

測試用例4:設定JVM參數-Xmx768m,運作程式觀察記憶體使用變化,會發現clean()後記憶體馬上下降,說明使用clean()方法能有效及時回收直接緩存。