问题描述
知情人士能否解释一下延迟支持的堆存储如何与 calloc/realloc 的内存归零保证交互?具体来说,我想知道:
- 如果/当零写入会导致存储立即出现故障
- 如果/如果不是,我是否应该关注可能发生故障的上下文(例如,从程序集完成的读取系统调用)
解决方法
calloc
可以从操作系统获得保证为零的页面,从而完全避免在用户空间中写入零。 (特别是对于大型分配,否则如果有任何大小合适的空闲列表条目,它会将空闲列表中的某些内容归零。)这就是懒惰的来源。
因此您的页面将从 mmap(MAP_ANONYMOUS)
新鲜出炉,不会受到用户空间的影响。读取它会触发一个软页面错误,写时复制将它映射到一个共享的物理页面零。 (非常有趣的事实,当在巨大的 calloc 分配上进行只读循环时,您可能会遇到 TLB 未命中但 L1d/L2 缓存命中。
写入该页面/其中一个页面(作为第一次访问,或者在 CoW 映射到零页面之后)将软页面错误,Linux 的页面错误处理程序将分配一个新的物理页面和零它。 (所以在缺页之后,整个页面通常在 L1d 缓存中是热的,或者至少是 L2,即使有 faultaround 准备更多的页面并将它们连接到页表中以减少页面错误的数量,如果有相邻的页面也是懒惰分配的)。
但是不,除了一般的性能调整之外,您通常不需要担心它。如果您在逻辑上拥有一些内存,您可以要求 read
将数据放入其中。 libc 包装器没有在那里做任何特殊的重试;所有的魔法(检查目标页面是否存在并将其像处理为软或硬页面错误)发生在内核的 read
实现中,作为 copy_to_user
的一部分。
(基本上是一个从内核内存到用户空间的 memcpy,如果你向内核传递一个你甚至不逻辑拥有的指针,通过权限检查可以使它返回 -EFAULT
. 即如果您从用户空间触摸它就会出现段错误的内存。请注意,您不会从 read(0,NULL,1)
获得 SIGSEGV,只是一个错误。使用 strace ./a.out
来查看,作为实际实现的替代方法在您的手写 asm 中进行错误检查。)