DirectByteBuffer記憶體申請與釋放
阿新 • • 發佈:2019-01-09
DirectByteBuffer類是在Java Heap外分配記憶體,對堆外記憶體的申請主要是通過成員變數unsafe來操作,下面介紹構造方法
// Primary constructor
//
DirectByteBuffer(int cap) { // package-private
super(-1, 0, cap, cap);
boolean pa = VM.isDirectMemoryPageAligned();//記憶體是否按頁分配對齊
int ps = Bits.pageSize();//獲取每頁記憶體大小
long size = Math.max(1L, (long)cap + (pa ? ps : 0));//分配記憶體的大小,如果是按頁對齊方式,需要再加一頁記憶體的容量
Bits.reserveMemory(size, cap);//用Bits類儲存總分配記憶體(按頁分配)的大小和實際記憶體的大小
long base = 0;
try {
base = unsafe.allocateMemory(size);//在堆外記憶體的基地址
} catch (OutOfMemoryError x) {
Bits.unreserveMemory(size, cap);
throw x;
}
unsafe.setMemory(base, size, (byte) 0);//初始化堆外記憶體的資料為0
if (pa && (base % ps != 0)) {
// Round up to page boundary
address = base + ps - (base & (ps - 1));//計算堆外記憶體的基地址
} else {
address = base;
}
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));//釋放記憶體會通過cleaner類操作
att = null;
}
假設堆外記憶體已經用了512K,pagesize=1024k,需要再分配 512個位元組,為了使記憶體按頁對齊,首先申請512+1024=1536個位元組,新分配記憶體的基地址base=512+1024-(512&1023)=1024。
DirectByteBuffer類的記憶體裡是在堆裡申請的,但是通過基類Buffer的capacity,long address兩個變數指向堆外的記憶體,如果在程式中建立了DirectByteBuffer類例項A,當A自身沒有被引用時,在觸發GC回收之前,jvm把A放在PhantomReference佇列裡,同時不斷掃描PhantomReference佇列,取出A,觸發new Deallocator裡的run方法回收堆外直接記憶體,同時回收A自身的堆記憶體.