什么是用户进程的有效地址空间? (OS X和Linux)

mmap系统调用文档说,如果出现以下情况,函数将失败:

指定了MAP_FIXED,并且addr参数不是页alignment的,或者所需地址空间的一部分驻留在用户进程的有效地址空间之外。

我无法在任何地方find说明什么是有效地图的文档。 (我有兴趣在OS X和Linux上执行此操作,理想情况下相同的地址对于这两个操作都是有效的)。

Solutions Collecting From Web of "什么是用户进程的有效地址空间? (OS X和Linux)"

Linux内核为自己保留了虚拟地址空间的一部分,用户空间几乎没有访问权限,不能映射任何东西。 你正在寻找所谓的“用户空间/内核空间拆分”。

在i386上默认是3G / 1G一个用户空间得到较低的3GB虚拟地址空间,内核得到1GB以上,另外还有2G / 2G和1G / 3G分裂:

 config PAGE_OFFSET hex default 0xB0000000 if VMSPLIT_3G_OPT default 0x80000000 if VMSPLIT_2G default 0x78000000 if VMSPLIT_2G_OPT default 0x40000000 if VMSPLIT_1G default 0xC0000000 depends on X86_32 

在x86_64上,用户空间位于(当前)48位虚拟地址空间的下半部分:

 /* * User space process size. 47bits minus one guard page. */ #define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE) 

这取决于许多因素,其中许多因素不受您的控制。 正如adobriyan所说,根据操作系统的不同,您有各种固定的上限,超出这个范围就是内核代码和数据。 通常这个上限在32位操作系统上至少为 2GB; 一些操作系统提供额外的地址空间。 64位操作系统通常提供由CPU支持的虚拟地址位数(通常至少为40位地址空间)控制的上限。 但是,还有其他因素无法控制:

  • 在最新版本的linux上,在/proc/sys/vm/mmap_min_addr配置的地址下方的mmap映射将被拒绝。
  • 您无法创建与任何现有映射重叠的映射。 由于动态链接器可自由映射任何与可执行文件的固定部分不重叠的地方,这意味着可能会拒绝任何地址。
  • 内核可能会注入其他映射,如系统调用门 。
  • malloc可以自己执行mmaps,它们被放置在某个任意位置

因此,绝对没有办法保证MAP_FIXED会成功,所以通常应该避免。

我所见过的唯一需要MAP_FIXED地方是wine启动代码,它保留了(使用MAP_FIXED )2G以上的所有地址,以避免混淆窗口代码,假设映射不会出现负面地址。 当然,这是对国旗的高度专业化使用。

如果你想这样做是为了避免在共享内存中处理偏移量,一个选择是将指针包装在类中以自动处理偏移量:

 template<typename T> class offset_pointer { private: ptrdiff_t offset; public: typedef T value_type, *ptr_type; typedef const T const_type, *const_ptr_type; offset_ptr(T *p) { set(p); } offset_ptr() { set(NULL); } void set(T *p) { if (p == NULL) offset = 1; else offset = (char *)p - (char *)this; } T *get() { if (offset == 1) return NULL; return (T*)( (char *)this + offset ); } const T *get() const { return const_cast<offset_pointer>(this)->get(); } T &operator*() { return *get(); } const T &operator*() const { return *get(); } T *operator->() { return get(); } const T *operator->() const { return get(); } operator T*() { return get(); } operator const T*() const { return get(); } offset_pointer operator=(T *p) { set(p); return *this; } offset_pointer operator=(const offset_pointer &other) { offset = other.offset; return *this; } }; 

注意:这是未经测试的代码,但应该给你基本的想法。