惰性过量分配和 calloc

l.k*_*l.k 1 c linux assembly calloc page-fault

知道的人可以解释一下延迟支持的堆存储如何与 calloc/realloc 的内存归零保证交互吗?具体来说,我想知道:

  1. 如果/当零写入会导致存储立即出现故障
  2. 如果/如果没有,我是否应该关注可能发生故障的上下文(例如,从程序集完成的读取系统调用)

Pet*_*des 5

calloc可以从操作系统获得保证为零的页面,从而完全避免在用户空间中写入零。(特别是对于大型分配,否则如果有任何大小合适的空闲列表条目,它将从空闲列表中清零。)这就是懒惰的来源。

所以你的页面将是新鲜的mmap(MAP_ANONYMOUS),不受用户空间的影响。读取它会触发一个软页面错误,即写时复制将它映射到一个共享的物理页面零。(非常有趣的事实,当在巨大的 calloc 分配上以只读方式循环时,您可能会遇到 TLB 未命中但 L1d/L2 缓存命中)。

写入该页面/其中一个页面(作为第一次访问,或者在它被 CoW 映射到零页面之后)将软页面错误,并且 Linux 的页面错误处理程序将分配一个新的物理页面并将其归零。(所以在缺页之后,整个页面通常在 L1d 缓存中是热的,或者至少是 L2,即使有 faultaround 准备更多的页面并将它们连接到页表中以减少页面错误的数量,如果有相邻的页面也被懒惰地分配)。


但是不,除了一般的性能调整之外,您通常不需要担心它。如果您在逻辑上拥有一些内存,您可以要求read将数据放入其中。libc 包装器没有在那里做任何特殊的重试;所有的魔法(检查目标页面存在和对待它就像一个软或硬页面错误)发生在内核的实现里面read,作为其一部分copy_to_user

(基本上是从内核内存到用户空间的 memcpy,-EFAULT如果您向内核传递一个您甚至在逻辑上都不拥有的指针,则可以通过权限检查使其返回。即,如果您从用户空间触摸它,则会出现段错误的内存。请注意,您不会从 获得 SIGSEGV read(0, NULL, 1),只是一个错误。strace ./a.out用于查看,作为在您的手写 asm 中实际实现错误检查的替代方法。)