zoukankan      html  css  js  c++  java
  • NIO中的heap Buffer和direct Buffer区别

    在Java的NIO中,我们一般采用ByteBuffer缓冲区来传输数据,一般情况下我们创建Buffer对象是通过ByteBuffer的两个静态方法:

    ByteBuffer.allocate(int capacity);
    ByteBuffer.wrap(byte[] array);

    查看相关的源码得到

    public static ByteBuffer allocate(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException();
        return new HeapByteBuffer(capacity, capacity);
    }
    public static ByteBuffer wrap(byte[] array,
                                    int offset, int length){
        try {
            return new HeapByteBuffer(array, offset, length);
        } catch (IllegalArgumentException x) {
            throw new IndexOutOfBoundsException();
        }
    }

    我们可以很清楚的发现,这两个方法都是实例化HeapByteBuffer来创建的ByteBuffer对象,也就是heap buffer. 其实除了heap buffer以外还有一种buffer,叫做direct buffer。我们也可以创建这一种buffer,通过ByteBuffer.allocateDirect(int capacity)方法,查看JDK源码如下:

    public static ByteBuffer allocateDirect(int capacity) {
        return new DirectByteBuffer(capacity);
    }
    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);
    
        long base = 0;
        try {
            base = unsafe.allocateMemory(size);
        } catch (OutOfMemoryError x) {
            Bits.unreserveMemory(size, cap);
            throw x;
        }
        unsafe.setMemory(base, size, (byte) 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));
        att = null;
    }

    那么heap buffer和direct buffer有什么区别呢?

    heap buffer这种缓冲区是分配在堆上面的,直接由Java虚拟机负责垃圾回收,可以直接想象成一个字节数组的包装类。

    direct buffer则是通过JNI在Java的虚拟机外的内存中分配了一块缓冲区(所以即使在运行时通过-Xmx指定了Java虚拟机的最大堆内存,还是可以实例化超出该大小的Direct ByteBuffer),该块并不直接由Java虚拟机负责垃圾回收收集,但是在direct buffer包装类被回收时,会通过Java Reference机制来释放该内存块。(但Direct Buffer的JAVA对象是归GC管理的,只要GC回收了它的JAVA对象,操作系统才会释放Direct Buffer所申请的空间)

    两者各有优劣势:direct buffer对比 heap buffer:

    劣势:创建和释放Direct Buffer的代价比Heap Buffer得要高;

    优势:当我们把一个Direct Buffer写入Channel的时候,就好比是“内核缓冲区”的内容直接写入了Channel,这样显然快了,减少了数据拷贝(因为我们平时的read/write都是需要在I/O设备与应用程序空间之间的“内核缓冲区”中转一下的)。而当我们把一个Heap Buffer写入Channel的时候,实际上底层实现会先构建一个临时的Direct Buffer,然后把Heap Buffer的内容复制到这个临时的Direct Buffer上,再把这个Direct Buffer写出去。当然,如果我们多次调用write方法,把一个Heap Buffer写入Channel,底层实现可以重复使用临时的Direct Buffer,这样不至于因为频繁地创建和销毁Direct Buffer影响性能。

    结论:Direct Buffer创建和销毁的代价很高,所以要用在尽可能重用的地方。 比如周期长传输文件大采用direct buffer,不然一般情况下就直接用heap buffer 就好。

    Refer:

    http://blog.csdn.net/u010853261/article/details/53464322

    https://www.jianshu.com/p/007052ee3773

    http://blog.csdn.net/xieyuooo/article/details/7547435

  • 相关阅读:
    保持URL不变和数字验证
    centOS ftp key?
    本地环境测试二级域名
    linux 解决You don't have permission to access 问题
    php smarty section loop
    php header Cannot modify header information headers already sent by ... 解决办法
    linux部分命令
    Linux 里面的文件操作权限说明
    用IT网络和安全专业人士视角来裁剪云的定义
    SQL Server 2008 R2炫酷报表"智"作有方
  • 原文地址:https://www.cnblogs.com/winner-0715/p/8590910.html
Copyright © 2011-2022 走看看