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

9

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

我这样说是不是有点挑剔,这只是DOS的遗留问题吗?那Linux呢?

编辑:

许多答案都提供了很好的细节,但没有一个回答我的问题。


虚拟地址空间是一种将内存从某个角度映射到另一个角度的方式。您不需要分配虚拟地址空间,而是需要分配内存,并将内存映射到您的地址空间中。 - Erik
标准中提到了“存储”:没有堆、没有虚拟地址空间、没有表格等。 - pmg
因此,正确的说法是“线程消耗1MB内存”,而不正确的说法是“线程消耗1MB虚拟地址空间”。 - Lukasz Madon
请查看我的回答更新。最好的描述是它消耗了1MB的匿名虚拟内存。 - R.. GitHub STOP HELPING ICE
15个回答

14

malloc 函数在堆上分配内存。

你的 C 库通常会维护一个可用内存块的列表(或更复杂的数据结构),找到一个适当的块来满足 malloc(可能将一个较大的块分割为多个较小的块),并将 free 的内存返回给列表(可能将几个较小的块合并成一个更大的块)。

仅当列表中没有足够大的块来满足你的 malloc 时,库才会向操作系统请求更多内存,例如使用 sbrk 系统调用。此系统调用返回的地址可能是虚拟地址或真实地址,这取决于你的硬件,但作为程序员,你不需要知道这一点。

malloc 函数分配的是虚拟地址空间而不是堆上的内存块,就像说 read 函数从硬盘而不是文件中读取数据一样:这在调用者的角度来看并不重要,而且并不总是正确的。


12

至少有三种方法可以测量内存消耗:

  • 虚拟地址空间 - 进程分配的地址空间数量。这也会影响到碎片和未来最大连续分配。
  • 提交指令 - 操作系统计算用于维护进程所分配的所有可写、非文件/设备支持内存所需的最大物理存储空间。如果操作系统允许其超过总物理内存+交换空间,则第一次写入超出部分时会发生非常糟糕的事情。
  • 物理内存 - 进程当前占用的物理资源数量(根据您的解释可能包括交换空间)。这可能小于提交指令,因为存在文件的全新零页和全新私有可写映射,或者多于提交指令,因为进程正在使用非可写或共享映射(但这些通常是可以进行交换/丢弃的)。

malloc通常会影响它们所有。

编辑:所以我能想到的最好的回答你的问题的方式是说:

malloc 分配 虚拟内存

而虚拟内存占用:

  • 虚拟地址空间
  • 提交指令
  • 如果写入了,则会占用物理资源。

在操作系统的保护下,进程无法了解物理内存,只知道虚拟内存。只有内存管理单元(MMU)知道物理内存的情况,软件程序员从不关心这一点。malloc 用于分配虚拟内存是对的,提交的内存是操作系统机制没错。我不明白你为什么要牵扯到物理内存。如果你的意思是实际物理内存已被占用,那当然会,因为虚拟内存映射到物理内存上。 - KeyC0de

12

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

简而言之: malloc 返回一个虚拟地址,并不会分配物理内存。

查看这里了解更多。


5

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

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

不能够用“在虚拟地址空间中分配内存”来精确描述malloc的操作,因为你的调用栈也是同一地址空间的一部分。


5
  • malloc() 会在堆上分配一块内存。

  • 它应该被称为虚拟地址空间吗?先别急。VAS(虚拟地址空间)是一个内存映射机制,包括整个应用程序的内存空间。换句话说,VAS 不仅限于堆的内存区域。实际上,堆只是其中的一部分。

每次运行新应用程序时,操作系统都会创建一个新进程并为应用程序分配新的 VAS。通过 malloc() 分配的内存保留在堆中,堆是 VAS 内的特殊内存区域,就像你所知道的那样,而通过标准方式分配的内存则会进入栈中,这是应用程序 VAS 内的另一个内存区域。


5
为了回答这个问题,我们需要知道我们正在处理什么类型的操作系统和架构。正如pmg所提到的,“标准”和文章都涉及“存储”或“空间”。除非我们做出一些假设,否则这些是最常见的术语,也是唯一有效的术语。
例如:
malloc在堆上分配一个虚拟地址空间块
对于许多嵌入式系统来说,这是不正确的。其中许多系统不使用虚拟内存,因为没有必要(没有多任务等)或出于性能原因。更重要的是,有可能某些奇特的设备没有堆的概念 - 怀疑会使用malloc,但是这正是标准引用“存储”的原因之一 - 它是实现特定的。
另一方面,这个例子在我们PC上的Windows和Linux中是正确的。让我们分析它来回答这个问题。
首先,我们需要定义什么是虚拟地址空间。
虚拟地址空间(VAS)是一种内存映射机制,有助于管理多个进程。
隔离进程-每个进程都有自己的地址空间 允许分配32位架构所限制的内存。 提供一种简明的内存模型
回到问题,“malloc是否在堆上分配内存块,还是应该称为虚拟地址空间?” 两种说法都是正确的。我宁愿说VAP而不是内存-这更加明确。有一个普遍的误解,即malloc = RAM内存。在旧日中,DOS内存分配非常简单。每当我们请求内存时,它总是RAM,但在现代操作系统中可能会有所不同。

非常清晰!malloc的返回地址可以是真实地址或虚拟地址,这取决于操作系统。对于调用者(应用程序)来说,它是没有意义的,只有对于操作系统才有意义。它唯一的使用场景是作为读/写操作的参数传递给操作系统。因此,只有操作系统使用它并解释它。所以它的值对应用程序来说是没有意义的。因为操作系统生成该地址,并且仅操作系统使用它。 - loin.liao

2

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


1

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

Malloc 管理一堆(或者甚至只是一部分)已映射的内存页面。这些页面称为堆。当一个人从 malloc 请求一定数量的字节时,malloc 将在它已经管理的页面中找到那个内存,或者它将向操作系统请求(在 Linux 上使用 brk 或 mmap)。这对于 malloc 的用户来说是完全透明的。

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


1

如果你仔细阅读了RTFM,你本可以自己回答这个问题的 :-)

特别是,在Linux机器上键入man malloc并逐个搜索“heap”和“virtual”,将让您明确地看到malloc()是基于heap内存而不是virtual内存定义的。

Wikipedia article关于malloc()的文章与Linux man页面一致。它指出(重点是我的):

在C语言中,库函数malloc用于在堆上分配一块内存。[...]一些平台提供了从C堆栈而不是堆(例如Unix alloca(),Microsoft Windows CRTL的malloca())运行时动态分配内存的库调用。当调用函数结束时,此内存会自动释放。C99标准的变化减少了对此的需求,该标准增加了支持在运行时确定大小的块范围的可变长度数组。

如果您对术语的含义感到困惑,那么维基百科上关于堆内存虚拟内存的文章可能会对您有所帮助。


0

malloc 在堆上分配一个块。对于分配的块跨越的每个内存页,可能会或可能不会在开始时将物理内存分配给它。整个块都是可用的,因为操作系统会处理页面故障并管理支持分配所需的物理/虚拟内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接