关于sbrk()和malloc()

5
我已经仔细阅读了关于sbrk()的Linux手册:
sbrk()更改程序断点的位置,该位置定义了进程数据段的结尾(即,程序断点是未初始化数据段结束后的第一个位置)。
我知道用户空间内存的组织方式如下: enter image description here 问题是: 当我调用sbrk(1)时,为什么它会说我正在增加堆的大小?正如手册所说,我正在改变“数据段和bss”的结束位置。因此,应该增加的是数据段和bss的大小,对吗?

提示:您的图表的哪一端对应着更高(数值更大)的地址,哪一端对应着较低的地址?栈是向哪个方向增长的?堆是向哪个方向增长的? - Jeffrey Bosboom
3
实际上,你的观点过于简单化,没有真正展示出发生的情况。请看我的回答。 - Basile Starynkevitch
2个回答

5
数据段和bss段是固定大小的。因此,分配给进程的空间不属于这些段的一部分,只是与它们相邻。这个空间称为堆空间,用于动态内存分配。
如果你想把它看作“扩展数据/bss段”,也可以。这不会对程序的行为、分配的空间或任何其他方面产生影响。
Mac OS X的手册页面指出,你不应该经常使用它们。
brk和sbrk函数是早期在虚拟内存管理出现之前遗留下来的历史珍品。brk()函数将进程数据段(未初始化数据)的断点或最低地址设置为addr(紧挨着bss的上方)。数据寻址被限制在addr和堆栈段的最低堆栈指针之间。brk通过页面大小片段分配内存;如果addr不能被系统页面大小整除,则增加到下一个页面边界。当前程序断点的值可通过sbrk(0)(也可参见end(3))可靠地返回。getrlimit(2)系统调用可用于确定数据段的最大允许大小;无法将断点设置超过从调用getrlimit返回的rlim_max值,例如etext + rlp->rlim_max(有关etext的定义,请参见end(3))。

尽管有查找指针,但我仍然无法找到end(3)的手册页面,这让我有点恼火。即使是这个(稍微有点陈旧的)sbrk()手册页面也没有它的链接。


那么,手册中给出的“程序中断是未初始化数据段结束后的第一个位置”相当令人困惑……因为未初始化数据段指的是bss的末尾,对吧? - Euclid Ye
这是来自FreeBSD的一个:end(3) - fuz

3
注意,现在很少使用sbrk(2)。大多数malloc实现都使用mmap(2) -至少对于大内存分配- 来获取一个内存段(并使用munmap释放它)。很多时候,free只是将一个内存区域标记为可供未来的malloc重用(而不是释放任何内存给Linux内核)。 (因此,现代Linux进程的堆由多个段组成,比您的图像更加复杂;而多线程进程每个线程有一个堆栈) 使用 proc(5),特别是 /proc/self/maps/proc/$pid/maps,来了解一些 进程虚拟地址空间。首先尝试理解 cat /proc/self/maps(显示该cat命令的地址空间)和 cat /proc/$$/maps(显示您的shell的地址空间)的输出。还可以尝试查看您的Web浏览器的maps伪文件(例如cat /proc/$(pidof firefox)/mapscat /proc/$(pidof iceweasel)/maps等); 我有超过一千行(因此有许多进程段)。
使用strace(1)可以了解给定命令或进程所执行的系统调用
在Linux上,大多数(可能全部)C标准库实现都是自由软件,因此您可以研究它们的源代码。musl-libc的源代码非常易于阅读。

了解 ELFASLR动态链接 & ld-linux(8),以及高级Linux编程书籍,然后查看syscalls(2)


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