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