malloc()如何知道堆的起始位置?

时间:2014-09-11 17:35:28

标签: c malloc heap

当操作系统将进程加载到内存中时,它会将堆栈指针初始化为虚拟地址,它确定堆栈应该进入进程的虚拟地址空间,程序代码使用此寄存器来知道堆栈变量的位置。我的问题是malloc()如何知道堆从哪个虚拟地址开始?堆是否总是存在于数据段的末尾,如果是这样,malloc()如何知道它在哪里?或者它甚至是一个连续的内存区域,还是随机散布在数据部分中的其他全局变量中?

3 个答案:

答案 0 :(得分:9)

malloc实现依赖于操作系统;他们用来获取堆的开头的过程也是如此。在UNIX上,这可以通过在初始化时调用sbrk(0)来完成。在其他操作系统上,过程是不同的。

请注意,您可以在不知道堆的位置的情况下实现malloc。您可以将空闲列表初始化为NULL,并在每次找到相应大小的免费元素时使用分配大小调用sbrk或类似函数。

答案 1 :(得分:2)

这只涉及malloc

的Linux实现

Linux或Posix上的许多malloc实现使用mmap(2)系统调用来获得相当大的内存范围。然后他们可以使用munmap(2)来释放它。

(看起来sbrk(2)可能不再使用了很多;特别是,它不是ASLR友好的,可能不是多线程友好的)

这些系统调用都可能非常广泛,因此有些实现会在相当大的块中询问内存(使用mmap)(例如,在一个或几兆字节的块中)。然后他们管理自由空间,例如它们将处理不同的小型malloc和大型malloc。

mmap系统调用通常不会开始在某些固定的部分给出内存范围(特别是因为ASLR

尝试使用您的系统运行一个简单的程序,打印单个malloc(例如128 int - s)的结果。您可能会在一次运行到另一次运行时观察到不同的地址(因为ASLR)。而且strace(1) - 它非常有启发性。另请尝试cat /proc/self/maps(或在程序中打印/proc/self/maps行)。见proc(5)

所以没有必要在某个地址“开始”堆,并且在许多系统上都没有任何意义。内核在随机页面上提供虚拟地址段。

顺便说一句,GNU libcmusl libc都是free software。您应该查看其malloc实现的源代码。我发现source code of musl libc非常易读。

答案 2 :(得分:0)

在Windows上,使用Heap functions获取进程堆内存。 C运行时将使用HeapAlloc在堆上分配内存块,然后使用它来完成malloc个请求。