在哪里可以详细了解
sbrk()
?
它到底是如何运作的?
在什么情况下我想用
sbrk()
来代替繁琐的malloc()
和new()
?
顺便说一句,
sbrk()
的扩展是什么?
查看 brk/sbrk 的规范。
该调用基本上要求操作系统通过将先前的“中断值”增加一定量来为应用程序分配更多内存。该数量(第一个参数)是您的应用程序获得的额外内存量。
大多数基本的 malloc 实现都基于 sbrk 系统调用构建,以获取它们分割和跟踪的内存块。 mmap 函数通常被认为是更好的选择(这就是为什么像 dlmalloc 这样的 malloc 都支持 #ifdef)。
至于“它是如何工作的”,最简单级别的 sbrk 可能看起来像这样:
uintptr_t current_break; // Some global variable for your application.
// This would probably be properly tracked by the OS for the process
void *sbrk(intptr_t incr)
{
uintptr_t old_break = current_break;
current_break += incr;
return (void*) old_break;
}
现代操作系统会做更多的事情,例如将页面映射到地址空间并为分配的每个内存块添加跟踪信息。
sbrk 已经过时了,现在您可以使用 mmap 将某些页面映射到 /dev/zero 之外。它当然不是您用来代替 malloc 和朋友的东西,它更多的是实现这些的一种方法。当然,它只存在于基于 posix 的操作系统上,这些操作系统关心对古代代码的向后兼容性。
如果您发现 Malloc 和 New 太麻烦,您应该考虑垃圾收集...但要注意,这会带来潜在的性能成本,因此您需要了解自己在做什么。
您永远不想使用
sbrk
代替 malloc
或 free
。它是不可移植的,通常仅由标准 C 库的实现者或在它不可用的情况下使用。它在其手册页中描述得很好:
描述
brk() 设置结束 数据段到指定的值 end_data_segment,当该值为 合理,系统确实有 内存足够,但进程没有 超过其最大数据大小(请参阅 设置限制(2))。
sbrk() 增加程序的数据 空间增量字节。 sbrk() 不是 一个系统调用,它只是一个C库 包装纸。调用 sbrk() 并使用 增量为 0 可以用来求 程序中断的当前位置。
返回值
成功后,brk() 返回 零,sbrk() 返回一个指向 新区域的开始。出错时, 返回 -1,并且 errno 设置为 ENOMEM。
最后,
malloc
和free
并不麻烦——它们是C中分配和释放内存的标准方法。即使你想实现自己的内存分配器,最好只使用malloc
和free
作为基础 - 一种常见的方法是使用 malloc
一次分配一个大块,并从中提供内存分配(这就是子分配器或池通常实现的)
关于名称
sbrk
(或其表弟 brk
)的由来,可能与堆的末尾由称为“break”的指针标记这一事实有关。堆在 BSS 段之后开始,通常朝堆栈方向增长。
您已经标记了这个 C++,那么为什么您要使用“麻烦的”malloc() 而不是 new 呢?无论如何,我不确定 malloc 有何麻烦;在内部也许是这样,但你为什么要关心呢?如果您确实关心(例如出于确定性的原因),您可以分配一个大池并为该池实现您自己的分配器。当然,在 C++ 中,您可以重载 new 运算符来做到这一点。
sbrk 用于将 C 库粘合到底层系统的操作系统内存管理。因此,进行操作系统调用而不是使用 sbrk()。至于它如何工作,那是依赖于系统的。例如,如果您正在使用 Newlib C 库(通常在带有 GNU 编译器的“裸机”嵌入式系统上使用),您必须自己实现 sbrk,因此它在这些情况下如何工作取决于您,只要它实现了扩展堆或失败所需的行为。
正如您从链接中看到的,它没有做太多事情,并且直接使用会非常麻烦 - 您可能最终会将其包装在 malloc 和 new 在任何情况下提供的所有功能中。