1. 程式人生 > >DirectByteBuffer記憶體申請與釋放

DirectByteBuffer記憶體申請與釋放

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自身的堆記憶體.