【发布时间】:2011-01-05 19:12:01
【问题描述】:
我在哪里可以详细了解sbrk()?
具体是如何工作的?
在什么情况下我想使用sbrk() 来代替繁琐的malloc() 和new()?
顺便说一句,sbrk() 的扩展是什么?
【问题讨论】:
我在哪里可以详细了解sbrk()?
具体是如何工作的?
在什么情况下我想使用sbrk() 来代替繁琐的malloc() 和new()?
顺便说一句,sbrk() 的扩展是什么?
【问题讨论】:
看看the specification for 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 库的实现者或在它不可用的情况下使用。它在man page 中有很好的描述:
说明
brk() 设置结束 数据段到指定的值 end_data_segment,当该值为 合理,系统确实有 足够的内存和进程没有 超过其最大数据大小(请参阅 setrlimit(2))。
sbrk() 增加程序的数据 按增量字节的空间。 sbrk() 不是 一个系统调用,它只是一个 C 库 包装。使用 sbrk() 调用 增量为 0 可用于查找 程序中断的当前位置。
返回值
成功时,brk() 返回 零,并且 sbrk() 返回一个指向 新区域的开始。出错时, 返回 -1,并将 errno 设置为 ENOMEM。
最后,malloc 和 free 并不繁琐——它们是在 C 中分配和释放内存的标准方式。即使你想实现自己的内存分配器,最好只使用 malloc 和 @ 987654328@ 作为基础 - 一种常见的方法是使用 malloc 一次分配一个大块并从中提供内存分配(这是子分配器或池通常实现的)
重新命名sbrk(或其表亲brk)的由来,它可能与堆的末尾由一个称为“break”的指针标记的事实有关。堆在 BSS 段之后开始,通常向堆栈增长。
【讨论】:
您已经标记了这个 C++,那么为什么要使用“繁琐”的 malloc() 而不是 new?无论如何,我不确定 malloc 有什么麻烦。内部可能是这样,但你为什么要关心?如果您确实关心(例如出于确定性的原因),您可以分配一个大池并为该池实现自己的分配器。在 C++ 中,你当然可以重载 new 运算符来做到这一点。
sbrk 用于将 C 库粘合到底层系统的操作系统内存管理。所以进行操作系统调用而不是使用 sbrk()。至于它是如何工作的,这取决于系统。例如,如果您使用 Newlib C 库(通常用于带有 GNU 编译器的“裸机”嵌入式系统),您必须 implement sbrk yourself,所以它在这些情况下的工作方式取决于您,只要它实现它需要扩展堆或失败的行为。
正如您从链接中看到的那样,它并没有做太多的事情,并且直接使用会非常很麻烦 - 您最终可能会将它包装在 malloc 和 new 提供的所有功能中无论如何。
【讨论】:
这取决于你所说的 malloc 是“繁琐”的意思。 sbrk 通常不再直接使用,除非您正在实现自己的内存分配器:IE,运算符覆盖“new”。即便如此,我也可能会使用 malloc 来给我最初的记忆。
如果您想了解如何在 sbrk() 之上实现 malloc(),请查看 http://web.ics.purdue.edu/~cs354/labs/lab6/,这是一个贯穿其中的练习。
不过,在现代系统上,您不应该触摸此界面。由于您调用 malloc 和 new 很麻烦,我怀疑您没有安全和正确地为您的代码使用 sbrk 的所有必要经验。
【讨论】: