出于某些目的,分配大量的虚拟空间会很有效,并且仅在被访问的页面中分配页面。分配大量内存是瞬时的,实际上并没有获取页面:
char* p = new char[1024*1024*1024*256];
好的,上面指出的是错误的,因为它是32位数字。
我希望new调用malloc来调用sbrk,并且当我访问起始位置以外的4Gb位置时,它将尝试将任务内存扩展那么多吗?
这是完整的程序:
#include <cstdint>
int main() {
constexpr uint64_t GB = 1ULL << 30;
char* p = new char[256*GB]; // allocate large block of virtual space
p[0] = 1;
p[1000000000] = 1;
p[2000000000] = 1;
}
现在,当我尝试分配大量内存时会得到bad_alloc,因此显然malloc无法正常工作。
我的印象是mmap可以映射到文件,但是由于建议这样做,所以我正在研究它。
好吧,因此mmap似乎支持分配虚拟内存的大区域,但是它需要文件描述符。创建巨大的内存中数据结构可能是一个胜利,但如果必须由文件支持,则不是这样:
即使我不喜欢附加到文件的想法,下面的代码也使用mmap。我不知道要在虚拟内存中放入多少数字,所以选择了0x800000000。 mmap返回-1,所以很明显我做错了:
#include <cstdint>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int main() {
constexpr uint64_t GB = 1ULL << 30;
void *addr = (void*)0x8000000000ULL;
int fd = creat("garbagefile.dat", 0660);
char* p = (char*)mmap(addr, 256*GB, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
p[0] = 1;
p[1000000000] = 1;
p[2000000000] = 1;
close(fd);
}
是否有任何方法可以分配大量的虚拟内存并稀疏访问页面,或者这不可行?
答案 0 :(得分:3)
256*GB
的值不适合32位整数类型的范围。尝试将uint64_t
作为GB
的一种类型:
constexpr uint64_t GB = 1024*1024*1024;
或者强制64位乘法:
char* p = new char[256ULL * GB];
OT:我更喜欢GB
的定义:
constexpr uint64_t GB = 1ULL << 30;
关于虚拟内存限制,请参见this answer。
答案 1 :(得分:3)
是否可以在linux中分配大量虚拟内存?
可能。但是您可能需要对其进行配置以使其被允许:
Linux内核支持以下过量使用处理模式
0-启发式过量使用处理。地址明显过量使用 空间被拒绝。用于典型的系统。它确保认真 狂放分配失败,同时允许过量使用以减少交换 用法。允许root在此分配更多的内存 模式。这是默认设置。
1-始终过量使用。适用于某些科学应用。 经典示例是使用稀疏数组的代码,仅依赖于 虚拟内存几乎完全由零页组成。
2-不要过度使用。系统的总地址空间提交 不允许超过交换+可配置的数量(默认为 50%)的物理RAM。在大多数情况下,取决于您使用的数量 情况,这意味着在访问过程中进程不会被杀死 页,但将在适当的内存分配上收到错误。
对于希望保证其内存的应用程序很有用 分配将在将来可用,而无需 初始化每个页面。
通过sysctl`vm.overcommit_memory'设置过量使用策略。
因此,如果您要分配的虚拟内存多于物理内存,那么您需要:
# in shell
sysctl -w vm.overcommit_memory=1
RLIMIT_AS进程的虚拟内存的最大大小(地址空间),以字节为单位。此限制影响对brk(2),mmap(2)和mremap(2)的调用,这些调用在超出此限制时会失败,并显示错误ENOMEM。自动堆栈扩展也会失败(并且如果没有通过sigaltstack(2)提供备用堆栈,则会生成SIGSEGV从而终止该进程)。由于该值很长,因此在32位长的计算机上,此限制最多为2 GiB,或者此资源是无限的。
所以,您想要:
setrlimit(RLIMIT_AS, {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
});
或者,如果您不能授予进程执行此操作的权限,则可以在/etc/security/limits.conf中永久配置此设置,这将影响(用户/组的)所有进程。
好,因此mmap似乎支持...,但是它需要文件描述符。 ...可能是一个胜利,但是如果必须要有文件支持的话就不是。。。我不喜欢附加文件的想法
您不需要使用文件支持的mmap。有MAP_ANONYMOUS。
我不知道要输入什么号码
然后使用null。示例:
mmap(nullptr, 256*GB, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
也就是说,如果您已经按照所述配置了系统,那么new
应该和mmap
一样好。可能会使用malloc
,而对于这样的大型分配,可能会使用mmap
。
奖金提示:利用HugeTLB Pages可能会受益。