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

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


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

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


这只关于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)

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

BTW,GNU libc和musl libc都是免费软件。 你应该看看他们的malloc实现的源代码。 我发现musl libc的源代码非常易读。


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

链接地址: http://www.djcxy.com/p/82377.html

上一篇: How does malloc() know where the heap starts?

下一篇: Segmentation registers use