DirectByteBuffer

DirectByteBuffer特性说明

 

Java 2 SE 6 doc :

Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer’s content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system’s native I/O operations.

  • DirectBuffer通过免去中间交换的内存拷贝, 提升IO处理速度;也就是常说的zero-copy

Java 2 SE 6 doc :

The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious.

  • DirectBuffer-XX:MaxDirectMemorySize=xxM大小限制下[1], 使用Heap之外的内存, GC对此”无能为力”[2] ,也就意味着规避了在高负载下频繁的GC过程对应用线程的中断影响.
  • 如果系统没有指定-XX:MaxDirectMemorySize,默认通-Xmx大小
  •        //directMemory  ,默认64M
           String s = (String)     properties.remove("sun.nio.MaxDirectMemorySize");
            if (s != null) if (s.equals("-1")) {
                directMemory = Runtime.getRuntime().maxMemory();
            } else {
                long l = Long.parseLong(s);
                if (l > -1L) directMemory = l;
            }
     

DirectByteBuffer如何内存回收

实现了一个Cleaner

 

cleaner = Cleaner.create(this, new Deallocator(base, size, cap));

 

 Deallocator,实现内存回收 

            if (address == 0) {
                // Paranoia
                return;
            }
            unsafe.freeMemory(address);
            address = 0;
            Bits.unreserveMemory(size, capacity);
        }
 

在什么时候被调用?

看看Reference里的奥秘,它内部有一个Thread ReferenceHandler,它的run 方法会调用Cleaner.clean

 

//截取部分代码
                Reference r;
                synchronized (lock) {
                    if (pending != null) {
                        r = pending;
                        Reference rn = r.next;
                        pending = (rn == r) ? null : rn;
                        r.next = r;
                    } else {
                        try {
                            lock.wait();
                        } catch (InterruptedException x) { }
                        continue;
                    }
                }

                // Fast path for cleaners
                if (r instanceof Cleaner) {
                    ((Cleaner)r).clean();
                    continue;
                }
 

 

DirectByteBuffer如何实现zero-copy

sun.nio.ch.IOUtil

 

    static int read(FileDescriptor filedescriptor, ByteBuffer bytebuffer, long l, NativeDispatcher nativedispatcher, Object obj)
        throws IOException
    {
        ByteBuffer bytebuffer1;
        if(bytebuffer.isReadOnly())
            throw new IllegalArgumentException("Read-only buffer");
        if(bytebuffer instanceof DirectBuffer)
            return readIntoNativeBuffer(filedescriptor, bytebuffer, l, nativedispatcher, obj);
        bytebuffer1 = null;
        int j;
        bytebuffer1 = Util.getTemporaryDirectBuffer(bytebuffer.remaining());
        int i = readIntoNativeBuffer(filedescriptor, bytebuffer1, l, nativedispatcher, obj);
        bytebuffer1.flip();
        if(i > 0)
            bytebuffer.put(bytebuffer1);
        j = i;
        Util.offerFirstTemporaryDirectBuffer(bytebuffer1);
        return j;
        Exception exception;
        exception;
        Util.offerFirstTemporaryDirectBuffer(bytebuffer1);
        throw exception;
    }
     NativeDispatcher的实现类SocketDispatcher的read方法是native

   static native int read0(FileDescriptor filedescriptor, long l, int i) throws IOException;

 

DirectByteBuffer用在什么地方

 

  • jetty用来处理和socket通信使用了DirectByteBuffer

 

附录:

-XX:MaxDirectMemorySize

This option specifies the maximum total size of java.nio (New I/O package) direct buffer allocations.

Format

-XX:MaxDirectMemorySize=size[g|G|m|M|k|K]

Example

java -XX:MaxDirectMemorySize=2g myApp

Default Value

    The default value is zero, which means the maximum direct memory is unbounded.

 

 

参考:http://www.tbdata.org/archives/801

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DirectByteBuffer 是 Java NIO 中提供的一种用于操作堆外内存的缓冲区类型。DirectByteBuffer 持有一个堆外内存的引用,当 DirectByteBuffer 对象被垃圾回收时,它所持有的堆外内存并不会自动被回收,这可能会导致内存泄露。 为了避免内存泄露,需要手动释放 DirectByteBuffer 所持有的堆外内存。一种常见的方法是通过调用 DirectByteBuffer 的 clean() 方法来释放堆外内存。但是,clean() 方法并不能保证立即释放堆外内存,而且它只能在 JDK 9 之前的版本中使用。 另外一种更可靠的方法是使用反射来调用 DirectByteBuffer 内部的 Cleaner 对象的 clean() 方法,这样可以保证及时释放堆外内存。示例代码如下: ``` import sun.misc.Cleaner; import java.lang.reflect.Field; import java.nio.ByteBuffer; public class DirectByteBufferUtil { private static final sun.misc.Unsafe UNSAFE; private static final long ADDRESS_OFFSET; private static final long CLEANER_OFFSET; static { try { Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); UNSAFE = (sun.misc.Unsafe) field.get(null); ADDRESS_OFFSET = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("address")); CLEANER_OFFSET = UNSAFE.objectFieldOffset(ByteBuffer.class.getDeclaredField("cleaner")); } catch (Exception ex) { throw new RuntimeException(ex); } } public static void free(ByteBuffer buffer) { long address = UNSAFE.getLong(buffer, ADDRESS_OFFSET); if (address != 0) { UNSAFE.putLong(buffer, ADDRESS_OFFSET, 0); Cleaner cleaner = (Cleaner) UNSAFE.getObject(buffer, CLEANER_OFFSET); if (cleaner != null) { cleaner.clean(); } } } } ``` 使用上述代码中的 free() 方法来释放 DirectByteBuffer 所持有的堆外内存,例如: ``` ByteBuffer buffer = ByteBuffer.allocateDirect(1024); // 使用 buffer 操作堆外内存 DirectByteBufferUtil.free(buffer); ``` 这样就可以释放 DirectByteBuffer 所持有的堆外内存了。需要注意的是,由于上述代码使用了 JDK 内部的类和方法,所以可能不具有可移植性,应该根据具体情况谨慎使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值