4

我已经彻底阅读了关于 sbrk() 的 linux 手册:

sbrk() 改变程序中断的位置,它定义了进程数据段的结束(即程序中断是未初始化数据段结束后的第一个位置)。

而且我确实知道用户空间内存的组织如下: 在此处输入图像描述

问题是: 当我调用 sbrk(1) 时,为什么它说我正在增加堆的大小?正如手册所说,我正在更改“数据段和 bss”的结束位置。那么,数据段和 bss 的大小应该增加多少,对吗?

4

2 回答 2

5

data 和 bss 段是固定大小的。因此,在这些段结束后分配给进程的空间不是这些段的一部分;它只是与它们相邻。该空间称为堆空间,用于动态内存分配。

如果您想将其视为“扩展数据/bss 段”,那也可以。它不会对程序的行为、分配的空间或任何东西产生任何影响。

Mac OS X 上的手册页表明你真的不应该经常使用它们:

brk 和 sbrk 函数是在虚拟内存管理出现之前的早期遗留下来的历史奇闻。brk()函数将进程数据段(未初始化的数据)的中断或最低地址设置为addr(紧接在 bss 之上)。数据寻址被限制在addr堆栈段的最低堆栈指针和最低堆栈指针之间。内存是按brk页面大小的块分配的;如果addr不能被系统页面大小整除,则增加到下一个页面边界。

程序中断的当前值由sbrk(0)(另见end(3))可靠地返回。getrlimit(2)系统调用可用于确定数据段的最大允许大小;将无法设置超出rlim_max调用返回的值的中断getrlimit,例如 etext + rlp->rlim_max(参见end(3)的定义etext)。

尽管有查看它的指针,但我找不到end(3)的手册页,这有点令人恼火。即使这个(有点旧的)手册页sbrk()也没有链接。

于 2015-12-13T07:23:22.090 回答
2

请注意,今天很少使用sbrk(2) 。大多数malloc实现都使用mmap(2) - 至少对于大型分配 - 来获取内存段(并munmap释放它)。很多时候,free只是简单地将内存区域标记为可供将来重用malloc (并且不会向Linux 内核释放任何内存)。

(实际上,现代 linux 进程的堆由几个段组成,所以比你的图片更微妙;多线程进程每个线程有一个堆栈)

使用proc(5)尤其是/proc/self/maps/proc/$pid/maps来了解某个进程的虚拟地址空间。首先尝试了解(显示该命令的地址空间)和(显示您的 shell 的地址空间)的输出。还可以尝试查看您的网络浏览器的伪文件(例如或等...);我里面有一千多行(所以处理段)。cat /proc/self/mapscatcat /proc/$$/mapsmapscat /proc/$(pidof firefox)/mapscat /proc/$(pidof iceweasel)/maps

使用strace(1)了解给定命令或进程完成的系统调用。

利用 Linux 上大多数(可能是所有)C 标准库实现都是免费软件的优势,因此您可以研究它们的源代码。musl-libc的源代码非常容易阅读。

还可以阅读ELFASLR动态链接ld-linux(8)以及Advanced Linux Programming一书,然后是syscalls(2)

于 2015-12-13T07:32:20.073 回答