为什么调用大尺寸的 mmap() 不会失败?
我尝试使用 mmap()
来操作虚拟内存。我想保留并提交一个内存区域。我测试了这段代码:
const unsigned long gygabyte = 1024 * 1024 * 1024;
const unsigned long gygabyteCount = 2;
const unsigned long maxCapacity = gygabyteCount * gygabyte;
int main()
{
char* pMemory;
pMemory = (char*)mmap(NULL, maxCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if ( mprotect(pMemory, maxCapacity, PROT_READ | PROT_WRITE) != 0 )
{
cout << "Memory Allocation has failed" << endl;
}
usleep(-1);
return 0;
}
我从终端运行了程序的多个副本(比如 6 个)。我从未在任何一处看到“内存分配失败”。我正在 64 位 Ubuntu 上运行,内存为 4GB。谁能告诉我一些关于这个的事情吗?
I try to use mmap()
to manipulate virtual memory. I want to reserve and commit a region of memory. I tested this code:
const unsigned long gygabyte = 1024 * 1024 * 1024;
const unsigned long gygabyteCount = 2;
const unsigned long maxCapacity = gygabyteCount * gygabyte;
int main()
{
char* pMemory;
pMemory = (char*)mmap(NULL, maxCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if ( mprotect(pMemory, maxCapacity, PROT_READ | PROT_WRITE) != 0 )
{
cout << "Memory Allocation has failed" << endl;
}
usleep(-1);
return 0;
}
I ran several copies of my program (say 6) from a terminal. I didn't ever see "Memory Allocation has failed" in any one. I'm running on 64-bit Ubuntu with 4GB RAM. Can anyone tell me something about this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
mmap
保留进程虚拟地址空间的一个区域,但不会立即为其分配物理 RAM。因此,在 64 位平台上,您可以保留大量数据而不会失败(尽管您仍然需要检查失败;您的示例代码不需要)。 RAM 的物理页稍后在访问内存时分配。mprotect
只是改变保留内存的读/写访问权限;它也不会将其驻留在 RAM 中。通过传递 PROT_READ | 可以获得相同的效果。 PROT_WRITE 而不是PROT_NONE
到mmap
,并删除对mprotect
的调用。如果您需要立即将内存驻留在 RAM 中,请使用
mlock
来实现。如果没有足够的可用 RAM,它将失败。在许多 Linux 平台(包括 Ubuntu)上,存在资源限制 (RLIMIT_MEMLOCK
),它限制任何进程可以锁定的内存量;您可以使用ulimit -l
进行调整。mmap
reserves a region of the process's virtual address space, but does not immediately allocate physical RAM for it. Therefore, on a 64-bit platform, you can reserve a vast amount without failure (although you still need to check for failure; your example code doesn't). Physical pages of RAM are allocated later when the memory is accessed.mprotect
just changes the read/write access of the reserved memory; it won't make it resident in RAM either. You would get the same effect by passingPROT_READ | PROT_WRITE
instead ofPROT_NONE
tommap
, and removing the call tomprotect
.If you need the memory to be resident in RAM straight away, then use
mlock
for that. It will fail if there isn't enough RAM available. On many linux platforms (including Ubuntu), there is a resource limit (RLIMIT_MEMLOCK
) which restricts how much memory any process can lock; you can adjust this withulimit -l
.mmap 对于准备所需内存的映射很有用,但它不会将其分配给您的程序。当您访问内存时,内核会负责分配内存,因此如果您不同时访问这 8GB,则可以在 4GB 内存上使用
mmap
-ing 8 GB。mmap is useful for preparing a mapping of the memory you ask for, but it does not allocate it to your program. The kernel takes care of allocating the memory when you access it, thus
mmap
-ing 8 GB is possible on a 4GB memory, if you do not access those 8GB simultaneously.您应该首先检查
mmap
的结果。如果返回MAP_FAILED
,则表示分配失败。内核实际上不会一次分配这么多内存,而是在访问该块的相应区域时按需映射物理或交换空间。在您的特定情况下,您不需要单独调用
mprotect
,因为可以在调用mmap
时为整个区域传递这些标志:You should first check the result of
mmap
. In case it returnsMAP_FAILED
, it means the allocation has failed. The kernel wouldn't actually allocate so much memory at once, but would rather map physical or swapped space on-demand when you access the corresponding regions of that block.In your particular case you don't need a separate call to
mprotect
, since passing these flags for the entire region can be made at the time of callingmmap
:首先,你必须告诉 Linux 你希望它进行提交统计:
否则它会保留传统的默认设置(从 Linux 还是一个玩具操作系统时开始),即允许无限制的过度使用,并使你的应用程序在物理内存耗尽时严重崩溃。
另外,正如其他人所说,您需要根据
MAP_FAILED
检查mmap
的返回值,并且不需要使用mprotect
。首先,只需将PROT_*
的正确值传递给mmap
即可。First, you have to tell Linux you want it to do commit accounting:
Otherwise it keeps the legacy default (from when Linux was a toy OS) of allowing unlimited overcommit and making your apps horribly crash when they run out of physical memory.
Also, as others have said, you need to check the return value of
mmap
againstMAP_FAILED
, and there's no need to usemprotect
. Simply pass the right values ofPROT_*
tommap
to begin with.