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
请求。