2021-2-21:Java File MMAP 中,對 MappedByteBuffer 進行讀寫,爲何最大隻能2GB-1B?

我們來看底層實現:對於所有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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章