Direct ByteBuffer學習


 ByteBuffer有兩種一種是heap ByteBuffer,該類對象分配在JVM的堆內存里面,直接由Java虛擬機負責垃圾回收,一種是direct ByteBuffer是通過jni在虛擬機外內存中分配的。通過jmap無法查看該快內存的使用情況。只能通過top來看它的內存使用情況。

JVM堆內存大小可以通過-Xmx來設置,同樣的direct ByteBuffer可以通過-XX:MaxDirectMemorySize來設置,此參數的含義是當Direct ByteBuffer分配的堆外內存到達指定大小后,即觸發Full GC。注意該值是有上限的,默認是64M,最大為sun.misc.VM.maxDirectMemory(),在程序中中可以獲得-XX:MaxDirectMemorySize的設置的值。

    @Test
    public void testBits() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
    {
//        System.out.println("maxMemoryValue:"+sun.misc.VM.maxDirectMemory()); 
        ByteBuffer buffer=ByteBuffer.allocateDirect(0);
        Class c = Class.forName("java.nio.Bits");  
        Field maxMemory = c.getDeclaredField("maxMemory");  
        maxMemory.setAccessible(true);  
        synchronized (c) {  
            Long maxMemoryValue = (Long)maxMemory.get(null);  
            System.out.println("maxMemoryValue:"+maxMemoryValue);  
        }  
    }

下面要談到垃圾回收機制:direct ByteBuffer通過full gc來回收內存的,direct ByteBuffer會自己檢測情況而調用system.gc(),但是如果參數中使用了DisableExplicitGC那么就無法回收該快內存了,-XX:+DisableExplicitGC標志自動將System.gc()調用轉換成一個空操作,就是應用中調用System.gc()會變成一個空操作。那么如果設置了就需要我們手動來回收內存了

    @Test
    public void testAllocateDirector() throws Exception{
        ByteBuffer buffer=ByteBuffer.allocateDirect(1024);
        Field cleanerField = buffer.getClass().getDeclaredField("cleaner");
        cleanerField.setAccessible(true);
        Cleaner cleaner = (Cleaner) cleanerField.get(buffer);
        cleaner.clean();
    }

那么除了FULL GC還有別的能回收direct ByteBuffer嗎?CMS GC會回收Direct ByteBuffer的內存,CMS主要是針對old space空間的垃圾回收。但是是Oracle JDK 6u32以后的版本

 

講了這么多談下使用場景

1:多用網絡編程中用到,實現zero copy,數據不需要再native memory和jvm memory中來回copy

2:由於造和析構Direct Buffer時間成本高,建議使用緩沖池,參見netty的實現


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM