Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 假设在使用mmap时未初始化的堆内存被初始化为零?_C_Heap Memory_Virtual Memory - Fatal编程技术网

C 假设在使用mmap时未初始化的堆内存被初始化为零?

C 假设在使用mmap时未初始化的堆内存被初始化为零?,c,heap-memory,virtual-memory,C,Heap Memory,Virtual Memory,我们知道,虽然加载程序总是将.bss内存位置(例如未初始化的全局C变量)初始化为零,但对于堆内存来说,情况并非如此。一个常见的错误是假设堆内存被初始化为零 但是通过mmap获得的分配内存呢?我们可以通过调用mmap来请求堆内存,用匿名文件(要求零页)映射堆中的区域,因此在这种情况下,我们可以安全地假设堆内存已初始化为零 而且,malloc实际上会在内部调用mmap来请求内存以进行大容量的分配,而对于小容量的分配,malloc仍然会在内部调用sbrk/brk。对于后者,我们当然不能假设堆内存被初始

我们知道,虽然加载程序总是将
.bss
内存位置(例如未初始化的全局C变量)初始化为零,但对于堆内存来说,情况并非如此。一个常见的错误是假设堆内存被初始化为零

但是通过
mmap
获得的分配内存呢?我们可以通过调用
mmap
来请求堆内存,用匿名文件(要求零页)映射堆中的区域,因此在这种情况下,我们可以安全地假设堆内存已初始化为零

而且,
malloc
实际上会在内部调用
mmap
来请求内存以进行大容量的分配,而对于小容量的分配,
malloc
仍然会在内部调用
sbrk
/
brk
。对于后者,我们当然不能假设堆内存被初始化为零


因此,当
malloc
实际上在内部调用
mmap
时,对于大容量的分配,我们仍然可以假设堆内存被初始化为零?我知道这仍然不是一个好的实践,我们不应该在所有情况下阅读假设0,但我只想确保我的理论是正确的,这样我就知道我对
mmap
的理解是正确的。

你的假设是错误的。在Linux上,
mmap
有一个选项
MAP\u UNINITIALIZED
,该选项可用于更快的分配

我们知道,虽然.bss内存位置(如未初始化的全局C变量)总是由加载程序初始化为零

我不知道-可能是加载程序,可能是链接到程序中的语言启动代码(例如“crt0.o”),可能是操作系统/内核提供了“新页面归零”的保证,而加载程序不必麻烦

但是mmap获得的分配内存又如何呢

谁的
mmap()
如何使用

对于POSIX;该规范不包括直接用于分配内存的
mmap()
。相反,您应该为打开的“内存对象”(例如,从“
posix\u typed\u mem\u open()
”)获取一个文件描述符,然后使用其文件描述符映射内存对象;用于创建“内存对象”的函数的规范大多只是说(很有意思的解释)“诸如此类,实现定义的,诸如此类,很抱歉,我们的规范直到太晚才出现。”。正因为如此,对于面积是否归零没有什么可说的

对于Linux,
mmap(…,MAP\u ANONYMOUS)
为您提供零页面,
mmap(…,MAP\u ANONYMOUS | MAP\u UNINITIALIZED)
可能不会

对于Windows,您不使用
mmap()
来分配内存-而是使用
VirtualAlloc()
来确保新内存归零

其他任何操作系统都可以做它感觉到的任何事情

一般而言;多任务操作系统必须担心安全问题(例如,一个进程释放的内存中的数据在被另一个进程分配后仍然可以访问),并且出于安全原因(和方便性),会用零填充页面

所以,当malloc实际上在内部调用mmap时,对于大容量的分配,我们仍然可以假设堆内存被初始化为零

你可以随心所欲地假设,直到你发现这个假设是错误的。这包括假设
malloc()
在内部调用
mmap()
(在某些条件下或任何条件下)。例如,C库可以在程序的
.bss
中保留大量空间,并将其用于
malloc()
,这样
malloc()
就永远不会使用
mmap()
sbrk()
(或
VirtualAlloc()
或…)

如果您确实知道
malloc()
从某个地方获得了底层内存,这确实保证了内存中充满了零(这几乎是不可能的,因为您可能会得到旧内存和新内存的混合);然后,您仍然不能假设
malloc()
(或该语言运行时环境的任何其他部分-启动代码、C库等)没有临时使用内存来存储某些元数据,并且仍然不能假设从
malloc()
分配的内存在获得它时仍然为零


请注意,堆可能会优化
calloc()
,这样,如果它知道内存已经被零填充(因为它保持跟踪,并且还知道底层内存最初来自提供保证的某个地方),它就不会无缘无故地用零填充内存。本质上,
calloc()
是“
malloc()
”(而不是“
malloc()
后跟
memset()
”)。

如果你想保证内存设置为零,我建议你使用
calloc
。我没有资格回答这个问题,但不要假设任何没有记录的东西。谁说“malloc仍然在内部调用sbrk/brk”?对于某些特定的实现可能是这样。如果未初始化的变量进入
.bss
,则它们是零初始化的。如果。这是一个有效的编译器选择,因为您可以覆盖这些零,而C只保证未初始化的变量是可写的。您不能假定未初始化的变量是可读的,更不用说该值为零了。@MSalters 6.9.2/2:对于具有文件作用域但没有初始值设定项、没有存储类说明符或具有存储类说明符
static
的对象,其标识符的声明构成了一个暂定定义。如果翻译单元包含一个或多个标识符的暂定定义,而翻译单元不包含该标识符的外部定义,则行为与翻译单元包含该标识符的文件范围声明完全相同,复合类型在t结尾