【问题标题】:About sbrk() and malloc()关于 sbrk() 和 malloc()
【发布时间】:2016-03-18 20:39:23
【问题描述】:

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

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

而且我知道用户空间内存的组织如下:

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

【问题讨论】:

  • 提示:图表的哪一端对应于更高(数值更大)的地址,哪一端对应于更低的地址?堆栈以哪种方式增长?堆以哪种方式增长?
  • 在实践中,您的图片非常幼稚,并没有真正显示正在发生的事情。看我的回答

标签: c linux operating-system sbrk


【解决方案1】:

data 和 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(参见end(3)了解etext的定义)。

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

【讨论】:

  • 那么,手册给出的“程序中断是未初始化数据段结束后的第一个位置”相当混乱......因为未初始化数据段是指bss结束,对吗?
  • 这是来自 FreeBSD 的一个:end(3).
【解决方案2】:

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

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

使用proc(5),尤其是/proc/self/maps/proc/$pid/maps,来理解某些process 中的virtual address space。首先尝试了解cat /proc/self/maps(显示该cat 命令的地址空间)和cat /proc/$$/maps(显示您的shell 的地址空间)的输出。还可以尝试查看您的 Web 浏览器的 maps 伪文件(例如 cat /proc/$(pidof firefox)/mapscat /proc/$(pidof iceweasel)/maps 等...);我有一千多行(所以处理段)。

使用strace(1) 了解给定命令或进程完成的system calls

利用 Linux 上大多数(可能是全部)C standard library 实现是free software,因此您可以研究它们的源代码。 musl-libc的源代码很容易阅读。

还可以阅读 ELFASLRdynamic linkingld-linux(8) 以及 Advanced Linux Programming 书籍以及 syscalls(2)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-29
    • 2019-10-08
    • 2011-12-03
    • 2011-07-03
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    相关资源
    最近更新 更多