您正在观察的是虚拟机溢出。
32 位进程只能访问 4GB 的虚拟地址空间。该虚拟地址空间必须容纳
- 您的过程文本
- 您加载的任何共享库的文本(libc、libdl、...)
- 至少一叠
- vsyscalls 的文本
- 堆
- 任何其他 VM 映射
操作系统通常会对 CPU 上的内存控制器进行编程,以便为内核页面(其中的 vsyscalls)保留(大部分)VM 空间,并将进程可用的内存限制在 4GB 以下。这曾经是虚拟机的一半,现在更少了。
glibc
的实现malloc
为您的堆保留一个(或多个)VM空间块,但它被编程为为共享映射留下足够的VM空间。因此,根据虚拟地址空间中的其他内容,您可能会在整个 VM 饱和之前遇到“内存不足”。
请咨询/proc/[pid]/maps
您的 VM 映射的位置。
使用完整 VM 的唯一方法是使用mmap
和系列调用在空闲 VM 中的任何位置分配内存。尝试:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
int main() {
char * page;
size_t memory_allocated = 0;
while ((page = mmap(NULL, sysconf(_SC_PAGE_SIZE)
, PROT_READ | PROT_WRITE
, MAP_ANON | MAP_PRIVATE, -1, 0))
!= MAP_FAILED) {
memory_allocated += sysconf(_SC_PAGE_SIZE);
// optionally touch the page
// otherwise the mapping won't use physical RAM/swap
// *page = 1;
}
fprintf(stderr, "Allocated %zu MiB\n", memory_allocated >> 20);
perror("mmap");
return 0;
}
请不要将此作为 64 位二进制文件尝试,因为它会尝试在那里使用高达 256TB 的 RAM。
在我的 Mac OS X 上,我得到:
$ gcc -m32 17935873.c
$ ./a.out
Allocated 3516 MiB
mmap: Cannot allocate memory