C语言 使用超出预期内存使用量的大型 mmap 调用是否存在性能成本?



编辑:在使用按需分页的系统上

对于初始化在程序持续时间内持久存在且需要动态内存量的数据结构,是否有任何理由不从一开始就 mmap 上限?

例如,一个数组将在整个程序的生命周期内持久存在,但其最终大小未知。我最熟悉的方法大致如下:

type * array = malloc(size);

当阵列达到容量时,将其加倍:

array = realloc(array, 2 * size);
size *= 2;

我知道如果阵列可能在执行过程中释放以便可以重用其 VM,这可能是最好的方法,但如果它是持久的,有什么理由不按如下方式初始化数组:

array = mmap(0,
huge_size, 
PROT_READ|PROT_WRITE, 
MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, 
-1, 0) 

这样元素就永远不需要复制。

编辑:专门针对使用按需分页的操作系统。

不要试图比标准库更聪明,除非你100%知道自己在做什么。

malloc()已经为您这样做了。如果您请求大量内存,malloc()mmap()专用内存区域。如果您担心的是执行size *= 2; realloc(old, size)的性能影响,那么只需在开始时malloc(huge_size),然后跟踪程序中实际使用的大小。除非你出于某种特定原因明确需要它,否则做一个mmap()真的没有意义:它在任何特定方面都不是更快或更好,如果malloc()认为需要它,它会为你做。

只要:

  • 您正在构建一个 64 位程序:即使在 64 位 CPU 上,32 位程序的虚拟空间也受到限制
  • 你的上限不会接近 2^47,就像数学推导的
  • 上限一样
  • 您可以崩溃作为内存不足故障模式
  • 您只能在启用了过度提交的系统上运行

作为旁注,这样做的最终用户应用程序可能希望从GHC的书中借用一页,并预先分配1TB,即使10GB就可以了。这种不切实际的大数量将确保用户不会将虚拟内存使用情况与物理内存使用情况混淆。

如果您知道浪费一大块内存(很可能是整个页面,可能是 4096 字节(不会导致您的程序或系统上运行的其他程序内存不足,并且您知道您的程序只会在 UNIX 机器上编译和运行,那么这种方法并没有错,但由于以下原因,它不是好的编程实践:

#include

在 C程序中malloc()free()使用的<stdlib.h>文件由 C 标准指定,但它是由操作系统的编写者专门为您的体系结构实现的。这意味着在编写这些函数时会记住您的特定系统,因此除非您比编写它的人更了解操作系统中内存管理的内部工作原理,否则不太可能找到一种偷偷摸摸的方法来提高内存分配效率。

此外,您包含在mmap()内容中的<sys/mman.h>文件不是 C 标准的一部分,并且只会在 UNIX 机器上编译,这降低了代码的可移植性。

还有一个非常好的机会(假设是UNIX环境(,malloc()realloc()已经使用mmap()幕后为您的进程分配内存,因此几乎可以肯定的是,只使用它们更好。(将其理解为"realloc 不一定主动为我分配更多空间,因为很有可能我的进程已经控制了一大块内存,可以满足我的新内存请求,而无需再次调用mmap()"(

希望对您有所帮助!

最新更新