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

30 浏览
0 Comments

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

为了某些目的,分配大量的虚拟空间并仅分配访问的页面是高效的。分配大量的内存是瞬间完成的,实际上并不会抓取页面:

char* p = new char[1024*1024*1024*256];

。如上所述是错误的,因为它是32位数字。我预计new调用了malloc,malloc调用了sbrk,当我访问起点4Gb之外的位置时,它试图扩展任务内存了那么多?这是完整的程序:

#include 
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 
#include 
#include 
#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);
}

。有没有办法分配大块虚拟内存并稀疏访问页面,或者这是不可行的?

admin 更改状态以发布 2023年5月24日
0
0 Comments

256*GB的值无法适应32位整数类型的范围。尝试使用uint64_t作为GB的类型:

constexpr uint64_t GB = 1024*1024*1024;

或者,强制进行64位乘法:

char* p = new char[256ULL * GB];


关于GB的定义,我更喜欢这种方式:

constexpr uint64_t GB = 1ULL << 30;


至于虚拟内存限制,请参见此答案

0
0 Comments

在Linux中是否可能分配大量虚拟内存?

可能是可以的。但您可能需要对其进行配置以允许这样做:

Linux内核支持以下超额分配处理模式

0 - 启发式超额分配处理。明显的地址空间超额分配将被拒绝。用于典型系统。它可以确保严重的恶性分配失败,同时允许超额分配以减少交换使用。在此模式下,root被允许稍微分配更多的内存。

1 - 总是超额分配。适用于某些科研应用程序。经典的例子是使用稀疏数组的代码,并仅仅依赖于几乎全部由零页面组成的虚拟内存。

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

非常适用于希望确保其内存分配在未来可用,而无需初始化每个页面的应用程序。

超额分配策略通过sysctl `vm.overcommit_memory'设置。

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

# in shell
sysctl -w vm.overcommit_memory=1

RLIMIT_AS进程虚拟内存(地址空间)的最大大小,以字节为单位。此限制影响对brk(2),mmap(2)和mremap(2)的调用,当超过此限制时,这些调用将出现ENOMEM错误。还将失败自动堆栈扩展(如果未通过sigaltstack(2)提供备用堆栈,则会生成SIGSEGV以终止进程)。

所以,你想要:

setrlimit(RLIMIT_AS, {
    .rlim_cur = RLIM_INFINITY,
    .rlim_max = RLIM_INFINITY,
});

或者,如果你不能给这个进程授权做到这一点,那么你可以在/etc/security/limits.conf中进行持久性配置,这将影响一个用户/组的所有进程。


你不需要使用文件支持的mmap。有MAP_ANONYMOUS可以用于这个。

我不知道要请求什么号码

那就用null。例如:

mmap(nullptr, 256*GB, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)

话虽如此,如果你按照所描述的配置了系统,那么new应该和mmap一样效果好。它可能会使用malloc,这可能会用于这样的大内存分配mmap


额外提示:你可能会从使用HugeTLB Pages受益。

0