给定进程中堆的界限是什么?我了解此问题可能没有简单的答案,因此我对以下具体答案感兴趣:
最佳答案
我假设您正在尝试在此处编写自己的堆分配器,并且从标记中假定您正在Linux中进行。
SunEric为您提供了可能使用的内存的有用指示,但是,可以使用的内存是操作系统为您提供的内存。 IE要使内存进入您的进程,您将需要调用操作系统以将虚拟内存映射到进程空间(及其后的一些物理内存)。 malloc()
为您对此进行抽象,并在C中实现“堆”。它可以通过两种方式获取其内存:
brk
系统调用(映射到C库brk
或sbrk
)mmap
与MAP_ANON
一起使用(或更准确地说,是底层系统调用mmap2
)。 brk
是为堆分配内存的经典方法,通常,当我们谈论“堆”时,我们是指以这种方式分配内存(尽管brk
可以用于分配堆以外的内存,并且堆项目可能位于其他地方) - 见下文)。 Here是brk
分配方式的一个很好的答案,我无法对其进行改进。内存使用的位置实际上是算术的结果。堆在加载时遵循程序的BSS-即BSS的值随着堆的扩展而增长,因此开始实际上是由OS和动态加载程序确定的。因此,堆的末端取决于堆的大小和堆的大小(即您将堆长到多大)。mmap
不太清晰。它需要一个addr
参数:因此,如果您使用
mmap
来获取特定堆项的空间(就像malloc
可能特别适用于大型对象),则操作系统会选择其位置(带或不带提示)。如果您使用MAP_FIXED
,它将为您提供确切的位置或失败。从这个意义上讲,您的堆(或其中的项目)可以在操作系统允许您映射内存的任何位置。您问是否有一种可移植的方法来找出堆的开始和结束位置。可移植意味着一种语言,我假设使用C。就
brk
类型堆而言,是的(可以移植)。 man end
提供:由于堆从加载时的
BSS
的末尾运行到运行时的BSS
的顶部,因此一种方法是将加载时的end
的值作为堆的底部开始,并将end
的值作为加载时的开始评估为堆的结尾。这会错过libc
本身和共享库可能在调用main()
之前分配内容的事实。因此,更保守的方法是说它是edata
和end
之间的区域,尽管严格来讲,这可能包括不在堆上的内容。如果您不是在C语言中刻薄,则需要使用类似的技术。进行``程序中断''(即内存空间的顶部)并减去为堆分配的最低地址。
如果要查看任意进程的堆的内存分配,请执行以下操作:
$ cat /proc/$$/maps | fgrep heap
01fe6000-02894000 rw-p 00000000 00:00 0 [heap]
将
$$
替换为您要检查的进程的PID。