这个困扰我。
malloc是否在堆上分配一块内存,还是应该称为虚拟地址空间?
我是挑剔的叫它虚拟地址空间或这只是DOS的遗产? 如何Linux?
编辑:
很多细节的答案,但他们都没有回答我的问题。
malloc
在堆上分配内存。
你的C库通常保留一个可用的内存块的列表(或者更复杂的数据结构),找到一个合适的块来满足一个malloc
(可能将一个较大的块分割成若干个较小的块),并将free
的内存返回给列表(可能将几个小块合并成一个更大的块)
只有当列表中没有足够大的块来满足你的malloc
,库才会向系统要求更多的内存,例如使用sbrk系统调用。 这个系统调用返回的地址可能是一个虚拟地址,或者是一个真实的地址,具体取决于你的硬件,但作为一个程序员你不能(也不需要)知道这一点。
说malloc
分配虚拟地址空间,而不是堆上的块,就像说读取从硬盘而不是从文件读取:从调用者的角度来看,这并不总是正确的。
至少有三种测量内存消耗的方法:
malloc
通常会影响它们全部。
编辑:所以,我能想到回答你的问题的最好方法是说:
malloc
分配虚拟内存 。
和虚拟内存消耗:
malloc是否在堆上分配一块内存,还是应该称为虚拟地址空间?
简短的回答:malloc在堆上分配内存。
由于你的调用堆栈本身是同一空间的一部分,所以说malloc在虚拟地址空间分配内存是不够精确的 。
malloc
是一个库调用。 在linux上,它又调用sbrk
系统调用。 sbrk
会增加堆的大小,但实际上并没有分配物理内存。 当进程试图访问这个地址时,会引发page fault
,然后内核分配实际的物理页面并映射到虚拟地址。
TL; DR: malloc
返回一个虚拟地址,不分配物理内存。
看看这个 。
malloc()
确实在HEAP上分配了一块内存。
它应该被称为虚拟地址空间吗? 坚持这个想法一秒钟。 VAS ( 虚拟地址空间 )是一种内存映射机制,包含应用程序的整个内存空间。 换句话说,VAS不限于HEAP的存储区域。 HEAP实际上只是另一部分。
每次运行新应用程序时,操作系统都会创建一个新的进程并为应用程序分配一个新的增值服务。 通过malloc()
分配的malloc()
被保留在HEAP中,这是VAS中的一个特殊的内存区域,正如你所知道的那样,通过标准方式分配的内存最终在栈中,这是位于VAS内部的另一个内存区域应用。
所有进程都在自己的虚拟地址空间内运行。 内存访问是由内存管理单元调解的。 如果内存被映射,则数据被加载或从相应的物理地址存储。 如果没有内存映射到指定的地址,则(内存管理单元(MMU)将触发异常。
Malloc管理着一堆(或者甚至只是一小部分)映射的内存页面。 这些页面被称为堆。 当从malloc请求一些字节时,malloc将在已经管理的页面中找到这个内存,或者向操作系统请求(在linux上使用brk或者mmap)。 这对malloc的用户是完全透明的。
所以这两个概念是完全正交的。 进程访问MMU可能转换成物理地址的虚拟内存,堆是由malloc管理的内存块。
你可以自己回答这个问题,如果你打扰到RTFM 🙂
特别是,在Linux机器上键入man malloc
并搜索(一次一个)“堆”和“虚拟”将使您明确地看到malloc()
是根据堆内存定义的,而不是虚拟内存。
malloc()
的Wikipedia文章与Linux手册页一致。 它指出(重点是我的):
在C中, 库函数
malloc
用于在堆上分配一块内存 。 有些平台提供的库调用允许从C栈而不是堆(例如Unixalloca()
,Microsoft Windows CRTL的malloca()
)进行运行时动态分配。 调用函数结束时,该内存将自动释放。 C99标准的改变减少了对此的需求,该标准增加了对在运行时确定大小的块范围的可变长度数组的支持。
如果您对术语的含义感到困惑,那么关于堆内存和虚拟内存的维基百科文章可能会对您有所帮助。
malloc
在堆上分配一个块。 对于分配的块所跨越的每个内存页面,开始时可能或可能没有提交给它的物理内存。 尽管整个模块都可用,因为操作系统将负责处理页面错误和管理支持分配所需的物理/虚拟内存。
答案取决于底层操作系统,libc实现和硬件体系结构。 在x86架构上运行大多数现代操作系统(如Linux或Windows)时,您将在线性地址空间中获得一个指针,但通常这取决于实现。 我怀疑,例如,在C中编程一些小的设备(如微控制器)时,malloc()会返回一个指向虚拟内存的指针,因为没有虚拟内存。
malloc在堆上分配,这是虚拟地址空间的一部分。
你没有被称为虚拟地址空间挑剔,你只是太笼统了。 可以比喻说:“你在浴室里呕吐。” 严格地说,这是真的,但“你在锅里呕吐”更准确,因为前者的说法意味着你可以在水池或浴缸里呕吐。
从概念上讲,大多数操作系统(包括Dos和Linux)支持malloc , 堆和虚拟内存 。
要回答这个问题,我们需要知道我们正在处理的是什么样的操作系统和体系结构。 正如pmg提到的标准和条款是指“存储”或“空间”。 除非我们做了大量的假设,否则这些是最通用的术语,也是唯一有效的术语。
例如:
malloc在堆上分配一个虚拟地址空间块
这对许多嵌入式系统来说是不正确的。 他们中的许多人不使用虚拟内存,因为没有必要(没有多任务等)或性能的原因。 更重要的是,一些奇特的设备可能没有堆的概念 – 怀疑是否会使用malloc,但这是标准提到“存储”的原因之一 – 它是特定于实现的。
另一方面,这个例子在我们的PC中是正确的。 让我们来分析它来回答这个问题。
首先,我们需要定义什么是虚拟地址空间。
虚拟地址空间(VAS)是一种内存映射机制,可以帮助管理多个进程。
回到问题,“malloc在堆上分配一块内存还是应该叫做虚拟地址空间?
两个陈述都是正确的 。 我宁愿说VAP而不是记忆 – 它更明确。 有一个共同的神话,malloc = RAM内存。 回到过去,DOS内存分配非常简单。 每当我们要求记忆时,它总是RAM,但在现代Oses中,它可能会有所不同。
malloc()
专门从堆中分配。
堆内存是否在虚拟地址空间中完全取决于操作系统和硬件体系结构。 在具有MMU和使用它的操作系统的系统上,即使物理到虚拟映射是存在于虚拟空间中的所有存储器(堆,代码空间,堆栈,静态存储器和存储器映射的I / O等)一个对一个。
要有一个虚拟地址空间需要一个MMU来映射物理地址到虚拟地址,并不是所有的目标都有一个MMU,所以堆内存和虚拟内存不是任何同义或可互换的概念; 他们完全是独立的概念。
关于“虚拟地址空间”作为“DOS的遗产”,你不可能说实话,16位x86架构完全不支持MMU或虚拟内存。 我想知道你是如何得到这个想法的?
内核和用户空间使用由内存管理硬件映射到物理地址的虚拟地址(也称为线性地址)。 这个映射是由操作系统设置的页表定义的。
通过内存分配的这个链接。