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

时间:2014-02-16 08:47:11

标签: c windows macos memory virtual

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

对于没有经过深入讨论的OSX,我一直在研究mach_vm_allocate(),mach_vm_map()等。例如,如果我想创建一组跨平台函数来公开Windows和OSX / iOS之间的常见虚拟内存功能,我会管理OSX上的提交/取消提交与Windows相比的区别吗?

我不确定我是否理解您是否可以保留虚拟地址范围并将其作为单独的操作提交,例如在Windows上?根据我的理解,mach_vm_allocate()类似于带有MEM_COMMIT |的VirtualAlloc() MEM_RESERVE并且还试图比较哪个实际上是一个更好的设计机制,如果有任何混淆。

我可能需要更好地了解页面管理器在OSX中的运行方式。

在Windows上,即使您提交了一个区域,我怀疑它可能实际上并没有用物理内存来支持它,除非您尝试访问它,除非可能存在大量内存 - 并且它只是保证在修改时支持交换文件。

在OSX上我不知道如何取消提交区域但仍然保留地址范围?例如,这种行为在64位程序(我最感兴趣的)中很有用,可以为具有倒带能力的竞技场/堆栈/线性分配器保留一个大的虚拟地址范围 - 这需要能够提交和取消提交地区的尽头。在Windows中很明显如何产生这样的行为,但在OSX中,我不太了解如何有效地复制它。

编辑:

我刚刚发现了这个:

Reserve memory on OS X

这与我的问题相关但肯定mmap()通过等效的mach_vm _ *()系统调用?

EDIT2:

典型的我现在发现这些:

Does mmap with MAP_NORESERVE reserve physical memory?

How can I reserve virtual memory in Linux?

但它仍然可能无法清除如何以我想要的方式取消提交 - 但是关于mmap()ANON的东西更多关于谷歌 - 并且可能看看我是否能找到mmap()源代码对于OSX(?)。

(当然有人会说使用mmap(),因为它可以在linux上工作,如果我可以找出去提交问题,但我仍然很好奇如何通过mach_vm _ *()调用路由...)< / p>

EDIT3:

我发现mremap()与mmap()一起看起来很有用!显然使用PROT_NONE,MAP_NORESERVE与mmap()看起来也很有趣。但是我仍然不确定如何取消提交区域但仍然保留地址范围,因为mremap()似乎无法使MAP_NORESERVE丢弃交换文件支持?

EDIT4:

我发现这个问题是de-commit:https://bugzilla.mozilla.org/show_bug.cgi?id=670596。讨论OSX和Linux上的行为是关于mprotect(addr,len,PROT_NONE)和madvise()的。 ..

EDIT5 :(!)

挖掘我发现的madvise()的Mac头文件:

#define MADV_WILLNEED POSIX_MADV_WILLNEED

#define MADV_DONTNEED POSIX_MADV_DONTNEED

#define MADV_FREE 5 / *页面不需要,丢弃内容* /

#define MADV_ZERO_WIRED_PAGES 6 / *将删除条目之前尚未取消的有线页面归零* /

#define MADV_FREE_REUSABLE 7 / *页面可以重复使用(任何人)* /

#define MADV_FREE_REUSE 8 / *调用者希望重用这些页面* /

#define MADV_CAN_REUSE 9

所以我猜MADV_FREE_REUSE应该是de-commits的首选用法?

EDIT6:我已经在iOS / OSX开发者论坛上提出了这个问题,同时我遇到过这些问题可能会对其他人有所帮助:

http://lists.apple.com/archives/PerfOptimization-dev/2009/Apr/msg00024.html http://markmail.org/message/yqwqd3zuawz6v5dd

还有:

http://fxr.watson.org/fxr/source/bsd/kern/kern_mman.c?v=xnu-1228;im=bigexcerpts#L824

关键是mmap(),madvise()或mach_vm_allocate()和mach_vm_behavior_set(),标志为VM_BEHAVIOR_DONTNEED。

在试验这个之后会报告给别人的利益......

EDIT7:

最新的mmap()和madvise()的OSX 10.9源代码我认为:http://www.opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/kern/kern_mman.c

似乎确认mach_vm_behavior_set()

EDIT8:

现在我可以告诉OSX 10.9:

http://www.opensource.apple.com/source/xnu/xnu-2422.1.72/osfmk/vm/vm_map.c

我应该使用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(?)

但我不确定这些意思到底是什么意思(?):

VM_BEHAVIOR_REUSABLE
VM_BEHAVIOR_REUSE
VM_BEHAVIOR_CAN_REUSE

我希望苹果确认首选使用模式,但我想我已接近回答上述问题......

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

2 个答案:

答案 0 :(得分:2)

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

vm_allocate()mmap()都会保留一个地址范围。它们也使得访问该范围内的地址的过程合法,此时页面将在必要时映射到物理内存。但是,在OS X上,我不相信这两种功能都会为地址范围保留后备存储(交换)。

如果你分配一些空间然后访问它,导致它被映射到RAM或交换,并且你想将它返回到刚分配但是清除RAM或交换的支持,我相信第二次调用{使用mmap()的{​​1}}即可。

答案 1 :(得分:2)

我在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

// dealloc并返回系统内存大小

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;

// deinit

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