mmap():将旧内存重置为零驻留状态 [英] mmap(): resetting old memory to a zero'd non-resident state

查看:136
本文介绍了mmap():将旧内存重置为零驻留状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个内存分配例程,它目前正在顺利运行.我通过mmap()从操作系统获得了4096字节的页面内存.当我启动内存分配器时,我使用mmap()分配了1g虚拟地址空间,然后在进行分配时,根据我的分配算法的细节将其划分为块.

我一时兴高采烈地分配多达1g的内存感到安全,因为我知道mmap()实际上不会在实际写入页面之前将页面放入物理内存中.

现在,使用我的分配器的程序可能会急需大量内存,在这种情况下,操作系统最终将必须将整个1gig的页面放入物理RAM.问题在于该程序可能随后进入休眠期,在此期间它将释放该1gig的大部分,然后仅使用最少的内存.但是,我在分配器的MyFree()函数中真正要做的就是翻转一些簿记数据,这些数据将以前使用的演出标记为空闲,但是我知道这不会导致操作系统从物理内存中删除这些页面. /p>

我不能使用诸如munmap()之类的东西来解决此问题,因为分配算法的性质使得它需要一个连续的内存区域,并且其中没有任何空洞.基本上,我需要一种方法来告诉操作系统听着,您可以将这些页面从物理内存中取出并清除为0,但是当我再次需要它们时,请立即对其进行重新映射,就好像它们是刚被mmap() "

解决这个问题的最佳方法是什么?

实际上,在写完所有内容之后,我才意识到我可以做一个munmap(),紧接着是一个新的mmap().那是正确的方法吗?我觉得可能有一些更有效的方法可以做到这一点.

解决方案

您正在寻找madvise(addr, length, MADV_DONTNEED).来自联机帮助页:

MADV_DONTNEED :不要指望在不久的将来访问. (暂时,应用程序已在给定范围内完成,因此内核可以释放与其关联的资源.)此范围内页面的后续访问将成功,但将导致从底层映射中重新加载内存内容文件(请参阅mmap(2))或按需填充零页面以进行映射,而无需基础文件.

请特别注意有关后续访问将如何成功但如何恢复为按需填零的语言(对于没有基础文件的映射).

您可以大声地选择munmap,然后紧接着另一个mmap也可以,但是由于不再跟踪单个连续区域的分配,可能会导致内核效率低下;如果存在许多此类取消映射和重新映射事件,则内核端数据结构可能会变得being肿.

顺便说一句,使用这种分配器非常重要,您要使用MAP_NORESERVE进行初始分配,然后在分配它时触摸每个页面,并捕获所有生成的SIGSEGV并导致分配失败. (并且您需要证明您的分配器为SIGSEGV安装了一个处理程序.)如果不这样做,您的应用程序将在禁用了内存过量使用的系统上无法正常工作.有关更多详细信息,请参见 mmap 联机帮助页.

I'm writing a memory allocation routine, and it's currently running smoothly. I get my memory from the OS with mmap() in 4096-byte pages. When I start my memory allocator I allocate 1gig of virtual address space with mmap(), and then as allocations are made I divide it up into hunks according to the specifics of my allocation algorithm.

I feel safe allocating as much as a 1gig of memory on a whim because I know mmap() doesn't actually put pages into physical memory until I actually write to them.

Now, the program using my allocator might have a spurt where it needs a lot of memory, and in this case the OS would have to eventually put a whole 1gig worth of pages into physical RAM. The trouble is that the program might then go into a dormant period where it frees most of that 1gig and then uses only minimal amounts of memory. Yet, all I really do inside of my allocator's MyFree() function is to flip a few bits of bookkeeping data which mark the previously used gig as free, but I know this doesn't cause the OS remove those pages from physical memory.

I can't use something like munmap() to fix this problem, because the nature of the allocation algorithm is such that it requires a continuous region of memory without any holes in it. Basically I need a way to tell the OS "Listen, you can take these pages out of physical memory and clear them to 0, but please remap them on the fly when I need them again, as if they were freshly mmap()'d"

What would be the best way to go about this?

Actually, after writing this all up I just realized that I can probably do an munmap() followed immediately by a fresh mmap(). Would that be the correct way to go about? I get the sense that there's probably some more efficient way to do this.

解决方案

You are looking for madvise(addr, length, MADV_DONTNEED). From the manpage:

MADV_DONTNEED: Do not expect access in the near future. (For the time being, the application is finished with the given range, so the kernel can free resources associated with it.) Subsequent accesses of pages in this range will succeed, but will result either in reloading of the memory contents from the underlying mapped file (see mmap(2)) or zero-fill-on-demand pages for mappings without an underlying file.

Note especially the language about how subsequent accesses will succeed but revert to zero-fill-on-demand (for mappings without an underlying file).

Your thinking-out-loud alternative of an munmap followed immediately by another mmap will also work but risks kernel-side inefficiencies because it is no longer tracking the allocation a single contiguous region; if there are many such unmap-and-remap events the kernelside data structures might wind up being quite bloated.

By the way, with this kind of allocator it's very important that you use MAP_NORESERVE for the initial allocation, and then touch each page as you allocate it, and trap any resulting SIGSEGV and fail the allocation. (And you'll need to document that your allocator installs a handler for SIGSEGV.) If you don't do this your application will not work on systems that have disabled memory overcommit. See the mmap manpage for more detail.

这篇关于mmap():将旧内存重置为零驻留状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆