为何两次获取的堆顶指针地址不一致?
为何两次获取的堆顶指针地址不一致?
嘿,这个问题踩中了很多人对堆初始化的认知盲区!你本来觉得“我没手动分配堆内存,堆顶肯定不会变”,但实际上程序背后的标准库已经悄悄搞事情啦~
咱们先看你的代码和输出:你第一次调用sbrk(0)后立刻打印,然后把第二次sbrk(0)的结果存到heapTop再打印,结果两个地址差了一大截。问题出在第一次printf的执行过程中——标准库的IO操作(比如printf)在首次被调用时,会初始化内部的缓冲区结构,而这些结构是需要从堆上分配内存的!
也就是说,当你执行第一个printf的时候,glibc(假设你用的是这个标准库)已经偷偷调用了sbrk来扩展堆空间,用来存放它自己的IO相关数据。所以第一次sbrk(0)拿到的是程序刚启动、标准库还没动手时的堆顶,而等你第二次调用sbrk(0)的时候,堆已经被标准库调整过了,地址自然不一样。
你可以做个小实验验证这个结论:把两次sbrk(0)的调用放在printf之前,像这样:
#include <stdio.h> #include <unistd.h> int main() { void *first = sbrk(0); void *second = sbrk(0); printf("first sbrk(0):%p\n", first); printf("second sbrk(0):%p\n", second); return 0; }
这时候你会发现两次输出的地址完全一致——因为中间没有执行任何会触发堆分配的操作,标准库还没机会调整堆顶。
总结一下:程序启动后,不是只有你手动调用malloc/free才会改变堆顶,标准库的内部初始化操作(比如IO、内存分配器的arena初始化)也会悄悄调用sbrk或者mmap来调整内存布局,这就是你看到地址不一致的原因啦。
备注:内容来源于stack exchange,提问作者João
相关产品推荐
相关产品推荐

