我正在阅读 TLPI,在第 4.4 节中:
系统调用不会为用于向调用者返回信息的缓冲区分配内存。相反,我们必须传递一个指向先前分配的正确大小的内存缓冲区的指针。这与一些分配内存缓冲区以将信息返回给调用者的库函数形成对比。
为什么系统调用不为这些情况分配内存?这是一种内存优化,允许用户使用现有缓冲区(而不是不必要地分配新内存)?还有其他原因吗?
答案1
许多开发人员忘记了这malloc()
不是一个系统调用;而是一个系统调用。它是一个 C 库函数。实际的内存分配是通过brk
系统调用的行为非常不同。
简而言之,程序只有一块分配的 RAM 用于存储malloc()
需要扩展的数据如果需要的话使用brk()
。但malloc
在使用 . 释放缓冲区后,可以轻松地重新使用缓冲区free()
。当缓冲区被释放时,它们(不一定)不会像以下那样返回到操作系统它们通常位于堆的中间。
现在回答你的问题:为什么系统调用不能在内部分配缓冲区?
内核不知道你的程序如何使用它的数据块。它不能假设您正在使用 C 库,否则malloc
它无法与该数据结构交互;它不确定您使用什么数据结构来分配缓冲区。这意味着它无法分配可以释放的缓冲区free()
。
理论上,它可以在未使用的地址空间中分配整个 RAM 页,但释放它们将需要一个全新的系统调用,开销非常大;这比free()
通常不导致系统调用的成本要高得多。这也会非常浪费,因为缓冲区比整个页面小得多。
最后,值得理解的是,在许多情况下,程序可能已经需要特定位置的数据。当代码只需要求系统调用将数据直接写入所需的位置时,根本不需要强制代码复制数据并释放页面。
答案2
当您希望内核分配内存时,您可以调用mmap()
.当你打电话时mmap()
,你必须选择你想要的标志。您希望您的分配是PROT_EXEC
、MAP_HUGE_2MB
、 或MAP_LOCKED
?您希望将其分配到特定地址 ( MAP_FIXED
) 吗?
因此,将分配分开会更简单。这意味着我们不需要在每个系统调用中为这些标志提供参数。
使用内核取消分配内存需要进行另一个系统调用:munmap()
。
速度更快德-allocate,如果您没有直接使用内核分配。 free()
不是系统调用,因此它比munmap()
.
还有历史原因。原始 UNIX 内核无法分配和释放任意内存页。您可以调用brk()
,这会增加堆内存的大小。您无法要求内核释放堆内的内存块。