2011-07-14 114 views
8

我明白,當一個直接的緩衝區被分配,它不受垃圾回收,但我想知道的是,如果包裝對象是垃圾回收。例如,如果我分配了一個新的DirectByteBuffer dbb,然後使用dbb.duplicate()複製(淺拷貝)它,我會在同一塊內存中創建兩個包裝。是否收集Java DirectByteBuffer包裝垃圾?

這些包裝是否被垃圾收集?如果我沒有

while(true){ 
    DirectByteBuffer dbb2 = dbb.duplicate(); 
} 

我最終會OOM自己嗎?

+0

其實,一個DirectByteBuffer和它的本地內存_might_可能被垃圾收集。它使用PhantomReference來釋放本機分配的內存。 –

回答

10

在Sun JDK,一個java.nio.DirectByteBuffer —通過ByteBuffer#allocateDirect(int) —創建具有sun.misc.Cleaner型,其延伸java.lang.ref.PhantomReference的場。

當此Cleaner(記住,的PhantomReference亞型)被收集並即將進入相關ReferenceQueue,通過嵌套式ReferenceHandler運行收集相關的線程有Cleaner情況下的一種特殊情況處理:它向下轉換和致電Cleaner#clean(),最終返回DirectByteBuffer$Deallocator#run(),然後調用Unsafe#freeMemory(long)。哇。

這很迂迴,我很驚訝沒有看到Object#finalize()在使用中的任何用途。 Sun開發人員必須有理由將其與收集和參考管理子系統更緊密地聯繫起來。

簡而言之,只要垃圾收集器有機會注意到放棄並且它的引用處理線程通過上述調用取得了進展,您將不會由於放棄對DirectByteBuffer實例的引用而耗盡內存。

+2

請注意,如果您使用'-XX:+ DisableExplicitGC',那麼您可能會遇到'allocateDirect'更多的'OutOfMemory'錯誤。分配會嘗試保留內存,如果不能觸發'PhantomReference'的回收,則調用'System.gc()'。 –

1

查看源代碼到DirectByteBuffer它只是返回一個新的實例,所以不,你不會自己OOM。

只要你的代碼的其餘部分不能保留對原始dbb的引用,那麼該對象將正常收到垃圾回收。額外的dbb2對象同樣會在不再有任何引用(即while循環的結尾)時收集垃圾。

2

直接ByteBuffer對象就像任何其他對象一樣:它可以被垃圾收集。

ByteBuffer對象爲GC'd(ByteBuffer未明確聲明,但由MappedByteBuffer的文檔暗示)時,直接緩衝區使用的內存將被釋放。

事情變得有趣的是當你用虛擬內存空間填充了直接緩衝區,但仍然有很多空間。事實證明(至少在Sun JVM上),在分配直接緩衝區時用完虛擬空間將觸發Java堆的GC。其中可能收集未引用的直接緩衝區並釋放其虛擬內存承諾。

如果您在64位機器上運行,您應該使用-XX:MaxDirectMemorySize,這會給您可以分配的緩衝區數量設置一個上限(並且在您達到該限制時觸發GC)。

+0

如何使用DirectByteBuffers幫助垃圾收集暫停,ala TerraCotta的BigMemory? –

+0

@李丕:因爲你可以在一個直接緩衝區中存儲很多序列化的Java對象。 – parsifal

-2

當directbytebuffer分配,它不屬於垃圾收集

你在哪裏會有這種想法?這是不正確的。你是否將它們與MappedByteBuffers混合?

+0

@downvoter爲什麼? – EJP