malloc 返回内存或虚拟地址空间

Posted

技术标签:

【中文标题】malloc 返回内存或虚拟地址空间【英文标题】:malloc returns memory or virtual address space 【发布时间】:2011-08-09 08:13:21 【问题描述】:

malloc 是在堆上分配一块内存还是应该称为虚拟地址空间?

我是挑剔地称它为虚拟地址空间还是这只是 DOS 的遗产? Linux 怎么样?

编辑:

很多答案都非常详细,但是没有一个回答我的问题。

【问题讨论】:

虚拟地址空间是一种将某物所见的内存映射内存的一种方式。你不分配虚拟地址空间,你分配内存,而内存映射到你的地址空间。 标准提到“存储”:没有堆,没有虚拟地址空间,没有表,... 那么正确的说法是“线程消耗 1MB 内存”,不正确的是“线程消耗 1MB 虚拟地址空间”? 查看我的答案的更新。最好的描述是它消耗了 1MB 的匿名虚拟内存。 【参考方案1】:

Malloc 总是返回虚拟地址,原因是当你调用 malloc 它实际上是一个调用系统调用的包装函数(系统调用是内核级指令的一个花哨的词)并且这个系统调用在你的内部分配一个虚拟内存堆段。但是当你想要访问分配的值(存储或加载指令)时,MMU 会引发页面错误,这基本上意味着这个虚拟页面没有物理内存,只有在那个时候操作系统才会为这个虚拟页面分配物理内存 .

【讨论】:

【参考方案2】:

malloc() 分配进程拥有的虚拟内存。

在执行过程中,操作系统可以多次将进程重新加载到物理内存中。操作系统将每个进程的虚拟地址映射到物理内存。进程不知道映射。

虚拟地址空间空间由

系统空间(驱动程序)和 用户空间(一个程序代码区域,一个用于动态内存分配的,以及一个用于变量、参数的堆栈 ,返回值等)

【讨论】:

【参考方案3】:

malloc 是一个库调用。在 linux 上,它依次调用sbrk 系统调用。 sbrk 会增加堆的大小,但实际上并不分配物理内存。当进程尝试访问该地址时,会引发page fault,然后内核分配实际的物理页面并映射到虚拟地址。

TL;DR:malloc 返回一个虚拟地址并且不分配物理内存。

签出this。

【讨论】:

【参考方案4】:

malloc() 专门从堆中分配。

堆内存是否在虚拟地址空间完全取决于操作系统和硬件架构。在具有 MMU 和使用它的操作系统的系统上,所有内存(堆、代码空间、堆栈、静态内存和内存映射 I/O 等)存在于虚拟空间中,甚至如果物理到虚拟映射是一对一的。

要有一个虚拟地址空间需要一个 MMU 将物理地址映射到虚拟地址,并不是所有的目标都有一个 MMU,所以堆内存和虚拟内存在任何方面都不是同义词或可互换的概念;它们是完全独立的概念。

关于“虚拟地址空间”是“DOS 的遗产”,事实并非如此,16 位 x86 架构根本不支持 MMU 或虚拟内存。不知道你是怎么想到的?

【讨论】:

【参考方案5】:

要回答这个问题,我们需要知道我们正在处理什么样的操作系统和架构。正如pmg提到的标准和文章是指“存储”或“空间”。这些是最通用的术语,也是唯一有效的术语,除非我们做出一堆假设。

例如:

malloc 分配一个虚拟块 堆上的地址空间

这对于许多嵌入式系统是不正确的。他们中的许多人不使用虚拟内存,因为不需要(不需要多任务等)或出于性能原因。更重要的是,一些奇异的设备可能没有堆的概念——怀疑会使用 malloc,但公平地说,这是标准提到“存储”的原因之一——它是特定于实现的。

另一方面,该示例适用于我们 PC 中的 Window 和 Linux。让我们分析它来回答问题。

首先,我们需要定义什么是虚拟地址空间。

虚拟地址空间 (VAS) 是一种内存映射机制,有助于管理多个进程。

隔离进程——每个进程都有 他自己的地址空间 允许分配 32 位的内存 架构仅限于。 提供一种简洁的内存模型

回到问题,“malloc 是在堆上分配一块内存还是应该将其称为虚拟地址空间?”

两种说法都是正确的。我宁愿说 VAP 而不是记忆——它更明确。 malloc = RAM 内存有一个常见的神话。回到过去,DOS 内存分配非常简单。每当我们要求内存时,它总是 RAM,但在现代 OS 中它可能会有所不同。

【讨论】:

很清楚!malloc的返回地址可以是真实地址也可以是虚拟地址,取决于操作系统。它对调用者(应用程序)没有意义,它只对操作系统有意义。它唯一使用的场景是作为操作系统读/写操作的参数。所以只有操作系统使用它,解释它。所以它的值对Application没有意义。因为操作系统生成该地址,并且只有操作系统使用它。【参考方案6】:

malloc 在堆上分配内存,周期。

您的 C 库通常会保留一个可用内存块的列表(或一些更复杂的数据结构),找到一个合适的块来满足 malloc(可能将一个较大的块分成多个较小的块)并返回 @987654324 @'d 内存到列表(可能将一些较小的块合并成一个更大的块)

当列表不包含足够大的块来满足您的 malloc 时,库将要求操作系统提供更多内存,例如使用sbrk 系统调用。此系统调用返回的地址可能是虚拟地址,也可能是真实地址,具体取决于您的硬件,但作为程序员,您无法(也不需要)知道这一点。

malloc 分配虚拟地址空间而不是堆上的块就像说read 从您的硬盘而不是从文件中读取:从调用者的角度来看是无关紧要的,而且并非总是如此。

【讨论】:

【参考方案7】:

如果您打扰到 RTFM,您可以自己回答这个问题 :-)

特别是,在 Linux 机器上键入 man malloc 并搜索(一次一个)“堆”和“虚拟”将让您清楚地看到 malloc() 是根据 定义的堆内存,而不是虚拟内存。

malloc() 的 Wikipedia article 与 Linux 手册页一致。它指出(重点是我的):

在 C 中,库函数malloc 是 用于分配一块内存 堆。 [...] 一些平台提供 允许运行时的库调用 从 C 堆栈动态分配 而不是堆(例如 Unix alloca(),Microsoft Windows CRTL malloca())。这段记忆是 通话时自动释放 功能结束。对此的需求是 因 C99 的变化而减少 标准,增加了对 块作用域的变长数组 大小在运行时确定。

如果您对术语的含义感到困惑,那么heap memory 和virtual memory 上的***文章可能会对您有所帮助。

【讨论】:

【参考方案8】:

malloc() 确实在 HEAP 上分配了一块内存。

应该叫虚拟地址空间吗?保持这个想法一秒钟。 VAS虚拟地址空间)是一种内存映射机制,包含应用程序的整个内存空间。换句话说,VAS 并不局限于 HEAP 的内存区域。 HEAP 实际上只是它的另一部分。

每次运行新应用程序时,操作系统都会创建一个新进程并为该应用程序分配一个新的 VAS。如您所知,通过malloc() 分配的内存保留在 HEAP 上,这是 VAS 中的一个特殊内存区域,通过标准方式分配的内存最终进入堆栈,这是位于 VAS 内部的另一个内存区域申请。

【讨论】:

【参考方案9】:

至少有 3 种衡量内存消耗的方法:

虚拟地址空间 - 分配所占用的进程地址空间量。这也会影响碎片化和您将来可以进行的最大连续分配。 commit fee - 这是操作系统对维护分配给进程的所有可写、非文件/设备支持的内存所需的最大可能物理存储空间的记帐。如果操作系统允许它超过总物理内存 + 交换,那么在第一次写入超出部分时可能会发生非常糟糕的事情。 物理内存 - 进程当前占用的物理资源量(可能包括交换,取决于您的解释)。由于原始零页和原始私有可写文件映射,这可能低于提交费用,或者由于进程正在使用的不可写或共享映射(但这些通常是可交换/可丢弃的),这可能高于提交费用。

malloc 通常会影响他们所有人。

编辑:所以,我能想到的回答您问题的最佳方式是:

malloc 分配虚拟内存

虚拟内存消耗:

虚拟地址空间, 承担费用,并且 物理资源(如果已写入)。

【讨论】:

在操作系统的掩护下,进程无法知道物理内存。它只知道虚拟内存。只有 MMU 知道物理内存,软件程序员从不关心这个。 malloc 分配虚拟内存是的。提交费用是一种操作系统机制是的。我不明白你为什么在这里涉及物理内存。如果你的意思是说实际的物理内存被消耗了,那当然是这样,因为虚拟内存被映射到物理内存。【参考方案10】:

Malloc 在堆上分配,这是虚拟地址空间的一部分。

称它为虚拟地址空间并不是在挑剔,你只是太笼统了。这可以比作说,“你在浴室里呕吐”。严格来说这是对的,但“You puke in the pot”更准确,因为前一种说法暗示你也可以在水槽或浴缸里呕吐。

从概念上讲,包括 Dos 和 Linux 在内的大多数操作系统都支持malloc、the heap 和 virtual memory。

【讨论】:

【参考方案11】:

malloc 是在堆上分配一块内存还是应该称为虚拟地址空间?

简短回答:malloc 在堆上分配内存。

说 malloc 在虚拟地址 [原文如此] 空间中分配内存还不够精确,因为您的调用堆栈本身就是同一空间的一部分。

【讨论】:

【参考方案12】:

所有进程都在自己的虚拟地址空间内运行。对内存的每次访问都由内存管理单元进行调解。如果内存被映射,数据要么从相应的物理地址加载或存储。如果没有内存映射到指定地址,(Memory Management Unit (MMU) 将触发异常。

Malloc 管理着一堆(甚至可能只是一小部分)映射的内存页。这些页面称为堆。当从 malloc 请求多个字节时,malloc 要么在它已经管理的页面中找到该内存,要么它会询问操作系统(在 linux 上使用 brk 或 mmap)。这对 malloc 的用户是完全透明的。

所以这两个概念是完全正交的。进程访问虚拟内存,MMU 可以将其转换为物理地址,而堆是由 malloc 管理的内存块。

【讨论】:

【参考方案13】:

答案取决于底层操作系统、libc 实现和硬件架构。对于在 x86 架构上运行的大多数现代操作系统(如 Linux 或 Windows),您将在线性地址空间内获得一个指针,但通常这取决于实现。例如,当用 C 语言编写一些小型设备(如微控制器)时,我怀疑 malloc() 会返回一个指向虚拟内存的指针,因为没有虚拟内存本身。

【讨论】:

【参考方案14】:

内核和用户空间使用由内存管理硬件映射到物理地址的虚拟地址(也称为线性地址)。 此映射由页表定义,由操作系统设置。

通过Memory Allocation 上的此链接。

【讨论】:

【参考方案15】:

malloc 在堆上分配一个块。对于分配的块跨越的每个内存页面,一开始可能有也可能没有物理内存。不过,整个块都是可用的,因为操作系统将负责处理页面错误并管理支持分配所需的物理/虚拟内存。

【讨论】:

以上是关于malloc 返回内存或虚拟地址空间的主要内容,如果未能解决你的问题,请参考以下文章

虚拟地址空间布局架构

malloc内存分配原理 [linux]--mallocbrkmmap

malloc内存分配原理 [linux]--mallocbrkmmap

探秘malloc是如何申请内存的

探秘malloc是如何申请内存的

在C语言中,如何给函数分配内存?