DirectByteBuffer

本文详细介绍了DirectBuffer的概念及其在Java NIO中的实现方式,包括不同模式下MappedByteBuffer的应用场景及注意事项。此外,还提供了如何手动清理DirectBuffer以避免内存泄漏的方法。

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

  • ByteBuffer
    • HeapByteBuffer
    • MappedByteBuffer
      • MappedByteBuffer.map(int mode,long position,long size);

 

READ_ONLY只读试图修改得到的缓冲区将导致抛出 ReadOnlyBufferException
READ_WRITE读/写对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他程序不一定是可见的
PRIVATE专用对得到的缓冲区的更改不会传播到文件,并且该更改对映射到同一文件的其他程序也不是可见的;相反,会创建缓冲区已修改部分的专用副本

 

 

分配java.nio.ByteBuffer.allocateDirect
释放sun.nio.ch.DirectBuffer.cleaner().clean()

 

可以通过参数 -XX:MaxDirectMemorySize= 设置其可使用的最大内存大小,当未设置时默认同 -Xmx 的大小。

各种应用

 

BigMemoryhttp://terracotta.org/products/bigmemoryBigMemory stores “big” amounts of data in machine memory for ultra-fast access
DirectMemoryhttp://incubator.apache.org/directmemory/Apache DirectMemory is a multi layered cache implementation featuring off-heap memory management (a-la BigMemory) to enable efficient handling of a large number of java objects without affecting jvm garbage collection performance
HugeCollectionshttps://code.google.com/p/vanilla-java/wiki/HugeCollectionsIf you want to efficiently store large collections of data in memory. This library can dramatically reduce Full GC times and reduce memory consumption as well

 

OutOfMemoryError

DirectBuffer 相关的内存泄漏参看Study_Java_HotSpot_OOME

参考资料

[1]. http://blog.youkuaiyun.com/fancyerii/article/details/7655451
[2]. http://lixjluck.iteye.com/blog/1130455
[3]. http://www.zhurouyoudu.com/index.php/archives/470/

 

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;

/**
 * {@link DirectByteBufferCleaner}
 *
 * @author <a href=mailto:zhong.lunfu@gmail.com>zhongl</a>
 * @created 2011-1-14
 */
public final class DirectByteBufferCleaner {
  private DirectByteBufferCleaner() {}

  public static void clean(final ByteBuffer byteBuffer) {
    if (!byteBuffer.isDirect()) return;
    try {
      Object cleaner = invoke(byteBuffer, "cleaner");
      invoke(cleaner, "clean");
    } catch (Exception e) { /* ignore */ }
  }

  private static Object invoke(final Object target, String methodName) throws Exception {
    final Method method = target.getClass().getMethod(methodName);
    return AccessController.doPrivileged(new PrivilegedAction<Object>() {
      @Override
      public Object run() {
        try {
          return method.invoke(target);
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
      }
    });
  }

}

 

DirectByteBufferJava 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、付费专栏及课程。

余额充值