Java直接內存

  • 直接內存申請空間其實是比較消耗性能,需要本地方法通過系統調用完成
  • 直接內存在IO讀寫上的性能要優於堆內存,所以直接內存特別適合申請以後進行多次讀寫
  • 堆外內存優勢在 IO 操作上,對於網絡 IO,使用 Socket 發送數據時,能夠節省堆內存到堆外內存的數據拷貝
  • 零拷貝

    • 複製很大的文件
    • 頻繁的IO操作,例如網絡併發場景
  • 不受JVM堆的大小限制
  • 會受到本機總內存(包括RAM及SWAP區或者分頁文件)的大小及處理器尋址空間的限制,可能會拋出OutOfMemoryError異常
  • 直接內存的最大大小可以通過-XX:MaxDirectMemorySize來設置,默認是64M
  • ByteBuffer.allocateDirect()
  • 由於申請內存前可能會調用 System.gc(),所以謹慎設置 -XX:+DisableExplicitGC 這個選項,這個參數作用是禁止代碼中顯示觸發的 Full GC
  • 回收

    • 自動回收
    • GC 時會掃描 DirectByteBuffer 對象是否有有效引用指向該對象,如沒有,在回收 DirectByteBuffer 對象的同時且會回收其佔用的堆外內存
    • 虛引用(Phantom Reference)

      • 也稱爲幽靈引用或者幻影引用
      • 一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。
      • 爲一個對象設置虛引用關聯的唯一目的就是能在這個對象被收集器回收時收到一個系統通知
      • GC過程中如果發現某個對象除了只有PhantomReference引用它之外,並沒有其他的地方引用它了,那將會把這個引用放到java.lang.ref.Reference.pending隊列裏,ReferenceHandler這個守護線程會處理pending隊列裏,執行一些後置處理,這裏是調用Cleaner的clean方法
      • 而DirectByteBuffer構造方法內創建了一個Cleaner對象, Cleaner繼承了PhantomReference,其referent爲DirectByteBuffer,也是通過Cleaner調用unsafe.freeMemory(address)來釋放直接內存
    • 手動回收

      • DirectByteBuffer 實現了 DirectBuffer 接口,這個接口有 cleaner 方法可以獲取 cleaner 對象。
      public static void clean(final ByteBuffer byteBuffer) {  
        if (byteBuffer.isDirect()) {  
            ((DirectBuffer)byteBuffer).cleaner().clean();  
        }  
      }
      • Netty 中的堆外內存池就是使用反射來實現手動回收方式進行回收的。
  • DirectByteBuffer 這個類是 JDK 提供使用堆外內存的一種途徑,當然常見的業務開發一般不會接觸到,即使涉及到也可能是框架(如 Netty、RPC 等)使用的,對框架使用者來說也是透明的
  • 發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章