2021-2-21:Java File MMAP 中,对 MappedByteBuffer 进行读写

我们来看底层实现:对于所有DirectByteBuffer的读写,都用到了Unsafe类的public native void putByte(Object o, long offset, byte x);方法,底层实现是:

unsafe.cpp

UNSAFE_ENTRY(void, Unsafe_SetNative##Type(JNIEnv *env, jobject unsafe, jlong addr, java_type x)) \
  UnsafeWrapper("Unsafe_SetNative"#Type); \
  JavaThread* t = JavaThread::current(); \
  t->set_doing_unsafe_access(true); \
  //获取地址
  void* p = addr_from_java(addr); \
  //设置值
  *(volatile native_type*)p = x; \
  t->set_doing_unsafe_access(false); \
UNSAFE_END \

那么这个获取地址的方法是啥样子呢?

unsafe.cpp

inline void* addr_from_java(jlong addr) {
  // This assert fails in a variety of ways on 32-bit systems.
  // It is impossible to predict whether native code that converts
  // pointers to longs will sign-extend or zero-extend the addresses.
  //assert(addr == (uintptr_t)addr, "must not be odd high bits");
  //转换为int
  return (void*)(uintptr_t)addr;
}

这里我们看到,转换地址会被强制转换为int类型,所以只能映射 2GB - 1B 。

但是为何-XX:MaxDirectMemory可以指定比2G大的值呢?因为对于分配的直接内存中的 buffer,有对一个 BitMap 管理他们的基址,可以保证映射出对的地址,类似于堆内存的基址映射。但是对于文件映射内存,JVM 没有维护这么一个基址,或者说觉得没必要(一般不会有直接操作这么大文件的这么大内容的需求,大于2GB-1B我们多映射两次自己维护就行了)。

微信搜索“我的编程喵”关注公众号,每日一刷,轻松提升技术,斩获各种offer

image

猜你喜欢

转载自blog.51cto.com/11418075/2633524
今日推荐