malloc函数是在堆上分配内存块还是应该称其为虚拟地址空间?
我这样说是不是有点挑剔,这只是DOS的遗留问题吗?那Linux呢?
编辑:
许多答案都提供了很好的细节,但没有一个回答我的问题。
malloc函数是在堆上分配内存块还是应该称其为虚拟地址空间?
我这样说是不是有点挑剔,这只是DOS的遗留问题吗?那Linux呢?
编辑:
许多答案都提供了很好的细节,但没有一个回答我的问题。
malloc
函数在堆上分配内存。
你的 C 库通常会维护一个可用内存块的列表(或更复杂的数据结构),找到一个适当的块来满足 malloc
(可能将一个较大的块分割为多个较小的块),并将 free
的内存返回给列表(可能将几个较小的块合并成一个更大的块)。
仅当列表中没有足够大的块来满足你的 malloc
时,库才会向操作系统请求更多内存,例如使用 sbrk 系统调用。此系统调用返回的地址可能是虚拟地址或真实地址,这取决于你的硬件,但作为程序员,你不需要知道这一点。
说 malloc
函数分配的是虚拟地址空间而不是堆上的内存块,就像说 read
函数从硬盘而不是文件中读取数据一样:这在调用者的角度来看并不重要,而且并不总是正确的。
至少有三种方法可以测量内存消耗:
malloc
通常会影响它们所有。
编辑:所以我能想到的最好的回答你的问题的方式是说:
malloc
分配 虚拟内存。
而虚拟内存占用:
malloc
是一个库调用。在 Linux 上,它会调用 sbrk
系统调用。 sbrk
将增加堆的大小,但不会实际分配物理内存。当进程尝试访问该地址时,会引发一个页面错误
,然后此时内核将分配实际的物理页并映射到虚拟地址。
简而言之: malloc
返回一个虚拟地址,并不会分配物理内存。
查看这里了解更多。
malloc是在堆上分配内存,还是应该称其为虚拟地址空间?
简短回答:malloc在堆上分配内存。
不能够用“在虚拟地址空间中分配内存”来精确描述malloc的操作,因为你的调用栈也是同一地址空间的一部分。
malloc()
会在堆上分配一块内存。
它应该被称为虚拟地址空间吗?先别急。VAS(虚拟地址空间)是一个内存映射机制,包括整个应用程序的内存空间。换句话说,VAS 不仅限于堆的内存区域。实际上,堆只是其中的一部分。
每次运行新应用程序时,操作系统都会创建一个新进程并为应用程序分配新的 VAS。通过 malloc()
分配的内存保留在堆中,堆是 VAS 内的特殊内存区域,就像你所知道的那样,而通过标准方式分配的内存则会进入栈中,这是应用程序 VAS 内的另一个内存区域。
malloc函数总是返回虚拟地址,原因是当你调用malloc时,实际上是一个包装函数,它调用了系统调用(系统调用是内核级指令的花哨说法),并在堆段内分配了虚拟内存。但当你想要访问分配的值(存储或加载指令)时,MMU会引发页面错误,这基本上意味着没有物理内存用于此虚拟页面,只有在这个时候操作系统才会为这个虚拟页面分配物理内存。
所有进程都在自己的虚拟地址空间内运行。每次访问内存都由内存管理单元进行中介。如果内存被映射,数据将从相应的物理地址加载或存储。如果没有内存映射到指定的地址,内存管理单元(MMU)将触发异常。
Malloc 管理一堆(或者甚至只是一部分)已映射的内存页面。这些页面称为堆。当一个人从 malloc 请求一定数量的字节时,malloc 将在它已经管理的页面中找到那个内存,或者它将向操作系统请求(在 Linux 上使用 brk 或 mmap)。这对于 malloc 的用户来说是完全透明的。
因此,这两个概念是完全正交的。进程访问虚拟内存,MMU 可能会将其转换为物理地址,而堆是由 malloc 管理的内存块。
如果你仔细阅读了RTFM,你本可以自己回答这个问题的 :-)
特别是,在Linux机器上键入man malloc
并逐个搜索“heap”和“virtual”,将让您明确地看到malloc()
是基于heap内存而不是virtual内存定义的。
Wikipedia article关于malloc()
的文章与Linux man页面一致。它指出(重点是我的):
在C语言中,库函数
malloc
用于在堆上分配一块内存。[...]一些平台提供了从C堆栈而不是堆(例如Unixalloca()
,Microsoft Windows CRTL的malloca()
)运行时动态分配内存的库调用。当调用函数结束时,此内存会自动释放。C99标准的变化减少了对此的需求,该标准增加了支持在运行时确定大小的块范围的可变长度数组。
malloc
在堆上分配一个块。对于分配的块跨越的每个内存页,可能会或可能不会在开始时将物理内存分配给它。整个块都是可用的,因为操作系统会处理页面故障并管理支持分配所需的物理/虚拟内存。