可以在Linux中分配大量的虚拟内存吗?

Dov*_*Dov 5 c++ linux memory-management virtual-memory

对于某些目的,分配大量的虚拟空间和仅在被访问的页面中的页面将是高效的。分配大量内存是瞬时的,实际上并没有获取页面:

char* p = new char[1024*1024*1024*256];
Run Code Online (Sandbox Code Playgroud)

好的,上面指出的是错误的,因为它是一个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;
}
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试分配大量内存时,我得到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);
}
Run Code Online (Sandbox Code Playgroud)

有什么方法可以分配大量的虚拟内存并稀疏访问页面,还是这样做不可行?

eer*_*ika 4

linux下可以分配大容量的虚拟内存吗?

可能吧。但您可能需要将其配置为允许:

Linux内核支持以下几种过载处理模式

0 - 启发式过量使用处理。明显的地址空间过量使用将被拒绝。用于典型系统。它确保严重的疯狂分配失败,同时允许过度使用以减少交换使用。在此模式下,root 可以分配稍多的内存。这是默认设置。

1 - 总是过度投入。适用于某些科学应用。典型的示例是使用稀疏数组并仅依赖于几乎完全由零页组成的虚拟内存的代码。

2 - 不要过度投入。系统的总地址空间提交不允许超过交换区 + 物理 RAM 的可配置量(默认为 50%)。根据您使用的数量,在大多数情况下,这意味着进程在访问页面时不会被终止,但会在适当的情况下收到内存分配错误。

对于希望保证其内存分配将来可用而无需初始化每个页面的应用程序非常有用。

过量使用策略是通过 sysctl ‘vm.overcommit_memory’ 设置的。

因此,如果您想分配比物理内存更多的虚拟内存,那么您需要:

# in shell
sysctl -w vm.overcommit_memory=1
Run Code Online (Sandbox Code Playgroud)

RLIMIT_AS 进程虚拟内存(地址空间)的最大大小(以字节为单位)。此限制会影响对 brk(2)、mmap(2) 和 mremap(2) 的调用,超过此限制后,这些调用会失败并出现错误 ENOMEM。此外,自动堆栈扩展也会失败(如果没有通过 sigaltstack(2) 提供可用的备用堆栈,则会生成 SIGSEGV 来终止进程)。由于该值是 long,因此在具有 32 位 long 的计算机上,此限制最多为 2 GiB,或者此资源是无限的。

所以,你想要:

setrlimit(RLIMIT_AS, {
    .rlim_cur = RLIM_INFINITY,
    .rlim_max = RLIM_INFINITY,
});
Run Code Online (Sandbox Code Playgroud)

或者,如果您无法授予进程执行此操作的权限,那么您可以在 /etc/security/limits.conf 中持久配置它,这将影响(用户/组的)所有进程。


好的,所以 mmap 似乎支持...但它需要一个文件描述符。...可能是一个胜利,但如果它们必须有文件支持则不然...我不喜欢附加到文件的想法

您不需要使用文件支持的 mmap。有 MAP_ANONYMOUS 来解决这个问题。

我不知道要输入什么号码来请求

然后使用空值。例子:

mmap(nullptr, 256*GB, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
Run Code Online (Sandbox Code Playgroud)

也就是说,如果您按照描述配置了系统,那么new应该可以像mmap. 它可能会使用mallocwhich 可能会用于mmap像这样的大分配。


额外提示:您可能会受益于使用HugeTLB Pages