1. 程式人生 > >Direct ByteBuffer可能會導致記憶體洩露的原因

Direct ByteBuffer可能會導致記憶體洩露的原因

Direct ByteBuffer是在不是在Java Heap分配記憶體,而是在C Heap分配記憶體,但Direct ByteBuffer分配出去的記憶體其實也是由GC負責回收的,Hotspot在GC時會掃描Direct ByteBuffer物件是否有引用,如沒有則回收其佔用的堆外記憶體。
有兩種可能會導致堆外的記憶體無法被回收:
1.在6u32前的版本里,CMS GC有bug會導致可能回收不掉
2.Direct ByteBuffer物件晉升到了Old區,只能等Full GC觸發(CMS GC的情況下等CMS GC),因此在Direct ByteBuffer使用較多,存活時間較長的情況下,有可能會導致堆外記憶體耗光(因為Direct ByteBuffer本身物件所佔用的空間是很小的)。 
Direct ByteBuffer物件本身是放在堆裡,但是一個物件佔用很少記憶體,主要是它關聯到堆外記憶體去, Direct ByteBuffer要full gc才能回收,所以如果堆記憶體用得少,堆外記憶體用得多,這樣不觸發full gc會導致堆外記憶體out of memory。
如何判斷是Direct ByteBuffer造成的:如碰到堆外記憶體佔用較多的場景,可以嘗試強制執行Full GC(強制的方法為執行jmap -histo:live)看看,多執行一兩次,如堆外記憶體下降的話,很有可能就是Direct ByteBuffer造成的,對於這種情況,通常下面的啟動引數就可解決。
怎麼解決:
最好是在啟動引數上增加-XX:MaxDirectMemorySize=x[m|g],例如-XX:MaxDirectMemorySize=500m
(在沒設定MaxDirectMemorySize引數的情況下,用jinfo -flag等方式會看到預設值是-1,但VM.maxDirectMemory這個方法裡發現是-1,則會以-Xmx作為預設值),此引數的含義是當Direct ByteBuffer分配的堆外記憶體到達指定大小後,即觸發Full GC(這段邏輯請見Bits.reserveMemory的程式碼),如Full GC後仍然分配不出Direct ByteBuffer需要的空間,則會報OOM錯誤: 
java.lang.OutOfMemoryError: Direct buffer memory
參考博文:http://m.blog.csdn.net/article/details?id=50317443