C OSX/iOS上的虚拟内存与Windows提交/保留行为

C OSX/iOS上的虚拟内存与Windows提交/保留行为,c,windows,macos,memory,virtual,C,Windows,Macos,Memory,Virtual,在比较OSX/iOS和Windows中的虚拟内存系统行为时,我有点困惑。与Windows VirtualAlloc()相关的函数及其在保留和实际内存提交和取消提交方面的行为相当简单 对于未充分讨论的OSX,我一直在研究mach_vm_allocate()、mach_vm_map()等。例如,如果我想创建一组跨平台函数来公开Windows和OSX/iOS之间的公共虚拟内存功能,我将如何管理OSX上的提交/取消提交与Windows之间的差异 因为我不确定我是否理解您是否可以保留虚拟地址范围,并将其作

在比较OSX/iOS和Windows中的虚拟内存系统行为时,我有点困惑。与Windows VirtualAlloc()相关的函数及其在保留和实际内存提交和取消提交方面的行为相当简单

对于未充分讨论的OSX,我一直在研究mach_vm_allocate()、mach_vm_map()等。例如,如果我想创建一组跨平台函数来公开Windows和OSX/iOS之间的公共虚拟内存功能,我将如何管理OSX上的提交/取消提交与Windows之间的差异

因为我不确定我是否理解您是否可以保留虚拟地址范围,并将其作为单独的操作提交(如在Windows上)?据我所知,mach_vm_allocate()与VirtualAlloc()类似,具有MEM_COMMIT | MEM_RESERVE,并且还试图比较哪种机制设计得更好(如果有任何机制令人困惑的话)

可能我需要更好地理解OSX中页面管理器的功能

在Windows上,即使您提交了一个区域,我怀疑在您尝试访问它之前,它实际上可能不会使用物理内存对其进行备份,除非当前有足够的内存,并且它只保证在修改时支持交换文件

在OSX上,我不知道如何取消提交区域,但仍然保留地址范围?例如,这种行为在64位程序(我最感兴趣的是)中非常有用,可以为具有倒带功能的arena/stack/linear分配器保留较大的虚拟地址范围,这需要能够提交和取消提交区域的末端。在Windows中,如何产生这种行为是显而易见的,但在OSX中,我不太明白如何有效地复制它

编辑:

我刚刚发现:

这与我的问题有关,但肯定mmap()会通过等效的mach_vm_*()系统调用吗

编辑2:

我现在发现:

但它可能仍然不清楚如何以我希望的方式取消提交-但是去谷歌搜索更多关于mmap()的东西-可能看看我是否能找到OSX(?)的mmap()源代码

(当然有人会说使用mmap(),因为它在linux上也可以工作,如果我能解决取消提交的问题,但我仍然很好奇,它是如何通过mach_vm_*()调用路由的…)

编辑3:

我发现mremap()和mmap()一起看起来很有用!显然,使用PROT_NONE时,使用mmap()映射NORESERVE看起来也很有趣。但我仍然不确定如何取消提交区域,但仍然保留地址范围,因为mremap()似乎无法使用MAP_NORESERVE放弃交换文件备份

编辑4:

我发现了以下内容:。它讨论了OSX和Linux上的行为,包括mprotect(addr、len、PROT_NONE)和madvise()

编辑5:(!)

查找madvise()的Mac头文件:

#定义MADV_WILLNEED POSIX_MADV_WILLNEED

#定义MADV_DONTNEED POSIX_MADV_DONTNEED

#定义MADV_FREE 5/*不需要的页面,放弃内容*/

#定义MADV_ZERO_WIRED_PAGES 6/*在删除条目之前,将尚未解除连接的WIRED PAGES归零*/

#定义MADV_FREE_可重用7/*页可重用(任何人)*/

#定义MADV_FREE_REUSE 8/*调用方希望重用这些页面*/

#定义MADV\u CAN\u重用9

所以我猜MADV_FREE_重用应该是反提交的首选用法

EDIT6:我在iOS/OSX开发者论坛上提出了这个问题,同时我也遇到了这些问题,这些问题可能对其他想知道同样问题的人有所帮助:

还包括:

看起来键是mmap()和madvise(),或者mach_vm_allocate()和mach_vm_behavior_set(),标记为vm_behavior_DONTNEED

将在尝试此功能后为他人的利益而报告

编辑7:

mmap()和madvise()的最新OSX 10.9源代码我认为:

似乎确认了马赫数vm行为集合()

编辑8:

好的,现在我可以从OSX 10.9中看出:

我应该使用mach_vm_allocate()和vm_map_behavior_set(),在Windows VirtualAlloc()的说法中,(提示性)标志也大致相同:

VM_BEHAVIOR_WILLNEED => Commit address range
VM_BEHAVIOR_DONTNEED => Decommit address range
VM_BEHAVIOR_FREE => Decommit and completely release address range(?)
但我不确定这些到底是什么意思(?):

我希望苹果能确认我的首选使用模式,但我想我已经接近于用上面的回答回答我自己的问题了


这是我第一次有幸钻研一些非常干净的开源代码:-)

没有精确的模拟。在Unix风格的操作系统中,可以访问分配的内存,这将导致它与物理内存或交换相关联。但并不总是保证分配的内存有足够的交换文件空间。因此,如果系统不能交换其他东西来释放RAM,那么它可能无法关联物理内存

vm\u allocate()
mmap()
都保留一个地址范围。它们还使进程访问该范围内的地址合法化,在这一点上,页面将被映射到物理内存(如有必要)。然而,在OSX上,我不认为这两个函数都为地址范围保留了后备存储(交换)


如果您分配一些空间,然后访问它,导致它被映射到RAM或交换,并且您希望将其返回到刚刚被分配的状态,但清除RAM或交换中的备份,我相信使用
MAP\u FIXED
mmap()
进行第二次调用可以做到这一点。

我在OS X和iOS上使用以下方法:

char* m_base = 0;
unsigned m_offset = 0;
unsigned MAX_SIZE = 1024 * 1024 * 10; // 10 Mb
//初始化和保留内存

kern_return_t err = vm_allocate(mach_task_self(), (vm_address_t*)&m_base, MAX_SIZE, VM_FLAGS_ANYWHERE);
//分配内存大小

size = (size + roundToPageSize - 1) & ~(roundToPageSize - 1);
char* address = m_base + m_offset;
kern_return_t err = vm_allocate(mach_task_self(), (vm_address_t*)&address, size, VM_FLAGS_FIXED|VM_FLAGS_OVERWRITE);
m_offset += size;
// now address points to allocated memory in reserved space
size = (size + roundTo - 1) & ~(roundTo - 1);
char* address = m_base + m_offset - size;
kern_return_t err = vm_deallocate(mach_task_self(), (vm_address_t)address, size);
m_offset -= size;
//解除锁定并返回系统内存大小

size = (size + roundToPageSize - 1) & ~(roundToPageSize - 1);
char* address = m_base + m_offset;
kern_return_t err = vm_allocate(mach_task_self(), (vm_address_t*)&address, size, VM_FLAGS_FIXED|VM_FLAGS_OVERWRITE);
m_offset += size;
// now address points to allocated memory in reserved space
size = (size + roundTo - 1) & ~(roundTo - 1);
char* address = m_base + m_offset - size;
kern_return_t err = vm_deallocate(mach_task_self(), (vm_address_t)address, size);
m_offset -= size;
//脱硝

kern_return_t err = vm_deallocate(mach_task_self(), (vm_address_t)m_base, MAX_SIZE);
m_base = 0;
m_offset = 0;

MAP_FIXED似乎说,如果可能,请使用特定的地址范围-因此您的意思是mmap()一个alread