我已经彻底阅读了关于 sbrk() 的 linux 手册:
sbrk() 改变程序中断的位置,它定义了进程数据段的结束(即程序中断是未初始化数据段结束后的第一个位置)。
问题是: 当我调用 sbrk(1) 时,为什么它说我正在增加堆的大小?正如手册所说,我正在更改“数据段和 bss”的结束位置。那么,数据段和 bss 的大小应该增加多少,对吗?
我已经彻底阅读了关于 sbrk() 的 linux 手册:
sbrk() 改变程序中断的位置,它定义了进程数据段的结束(即程序中断是未初始化数据段结束后的第一个位置)。
问题是: 当我调用 sbrk(1) 时,为什么它说我正在增加堆的大小?正如手册所说,我正在更改“数据段和 bss”的结束位置。那么,数据段和 bss 的大小应该增加多少,对吗?
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()
也没有链接。
请注意,今天很少使用sbrk(2) 。大多数malloc
实现都使用mmap(2) - 至少对于大型分配 - 来获取内存段(并munmap
释放它)。很多时候,free
只是简单地将内存区域标记为可供将来重用malloc
(并且不会向Linux 内核释放任何内存)。
(实际上,现代 linux 进程的堆由几个段组成,所以比你的图片更微妙;多线程进程每个线程有一个堆栈)
使用proc(5)尤其是/proc/self/maps
和/proc/$pid/maps
来了解某个进程的虚拟地址空间。首先尝试了解(显示该命令的地址空间)和(显示您的 shell 的地址空间)的输出。还可以尝试查看您的网络浏览器的伪文件(例如或等...);我里面有一千多行(所以处理段)。cat /proc/self/maps
cat
cat /proc/$$/maps
maps
cat /proc/$(pidof firefox)/maps
cat /proc/$(pidof iceweasel)/maps
利用 Linux 上大多数(可能是所有)C 标准库实现都是免费软件的优势,因此您可以研究它们的源代码。musl-libc的源代码非常容易阅读。
还可以阅读ELF、ASLR、动态链接和ld-linux(8)以及Advanced Linux Programming一书,然后是syscalls(2)