为什么我们需要将缓冲区传递给系统调用才能返回信息?为什么系统调用不能在内部分配缓冲区?

为什么我们需要将缓冲区传递给系统调用才能返回信息?为什么系统调用不能在内部分配缓冲区?

我正在阅读 TLPI,在第 4.4 节中:

系统调用不会为用于向调用者返回信息的缓冲区分配内存。相反,我们必须传递一个指向先前分配的正确大小的内存缓冲区的指针。这与一些分配内存缓冲区以将信息返回给调用者的库函数形成对比。

为什么系统调用不为这些情况分配内存?这是一种内存优化,允许用户使用现有缓冲区(而不是不必要地分配新内存)?还有其他原因吗?

答案1

许多开发人员忘记了这malloc()不是一个系统调用;而是一个系统调用。它是一个 C 库函数。实际的内存分配是通过brk系统调用的行为非常不同。

简而言之,程序只有一块分配的 RAM 用于存储malloc()需要扩展的数据如果需要的话使用brk()。但malloc在使用 . 释放缓冲区后,可以轻松地重新使用缓冲区free()。当缓冲区被释放时,它们(不一定)不会像以下那样返回到操作系统它们通常位于堆的中间

现在回答你的问题:为什么系统调用不能在内部分配缓冲区?

内核不知道你的程序如何使用它的数据块。它不能假设您正在使用 C 库,否则malloc它无法与该数据结构交互;它不确定您使用什么数据结构来分配缓冲区。这意味着它无法分配可以释放的缓冲区free()

理论上,它可以在未使用的地址空间中分配整个 RAM 页,但释放它们将需要一个全新的系统调用,开销非常大;这比free()通常不导致系统调用的成本要高得多。这也会非常浪费,因为缓冲区比整个页面小得多。

最后,值得理解的是,在许多情况下,程序可能已经需要特定位置的数据。当代码只需要求系统调用将数据直接写入所需的位置时,根本不需要强制代码复制数据并释放页面。

答案2

当您希望内核分配内存时,您可以调用mmap().当你打电话时mmap(),你必须选择你想要的标志。您希望您的分配是PROT_EXECMAP_HUGE_2MB、 或MAP_LOCKED?您希望将其分配到特定地址 ( MAP_FIXED) 吗?

因此,将分配分开会更简单。这意味着我们不需要在每个系统调用中为这些标志提供参数。

使用内核取消分配内存需要进行另一个系统调用:munmap()

速度更快-allocate,如果您没有直接使用内核分配。 free()不是系统调用,因此它比munmap().

还有历史原因。原始 UNIX 内核无法分配和释放任意内存页。您可以调用brk(),这会增加堆内存的大小。您无法要求内核释放堆内的内存块。

相关内容