最近打了天津市赛和长城杯,遇到了好多堆题,也确实要走出舒适区了,但是没想到一上来给自己放了个大的。
堆和栈都是一种数据结构,但是并不像我们平时做的栈题,堆题的思路一般是从堆的创建销毁入手的,而栈一般都是程序创建好的,个别情况需要我们自己构建栈(这个另说)。堆和栈在程序中都是线性存储数据的,和算法里面的堆还不太一样(目前看来)。栈是从高地址向低地址伸展,而堆是从低地址向高地址伸展。栈一般都在函数的运行空间里,而堆一般都在程序bss段的高地址处。
在程序运行过程中,堆可以提供动态分配的内存,允许程序申请大小未知的内存。堆其实就是程序虚拟地址空间的一块连续的线性区域。我们称管理堆的那部分程序为堆管理器。目前Linux标准发行版中使用的堆分配器是glibc中的ptmalloc2
_libc_malloc
一般情况下我们会使用malloc函数来申请内存块,可是仔细看glibc的源码实现时,其实并没有malloc函数。其实该函数真正调用的是libc_malloc函数。为什么不直接写一个malloc函数呢?因为有时候我们可能需要不同的名称。此外,libc_malloc函数只是用来简单封装_int_malloc函数。_int_malloc函数才是申请内存块的核心。下面我们来仔细分析一下具体的实现。
该函数会首先检查是否有内存分配函数的钩子函数(__malloc_hook),这个主要用于用户自定义的堆分配函数,方便用户快速修改堆分配函数并进行测试。这里需要注意的是,用户申请的字节一旦进入申请内存函数中就变成了无符号整数。
// wapper for int_malloc
void *__libc_malloc(size_t bytes) {
mstate ar_ptr;
void * victim;
// 检查是否有内存分配钩子,如果有,调用钩子并返回.
void *(*hook)(size_t, const void *) = atomic_forced_read(__malloc_hook);
if (__builtin_expect(hook != NULL, 0))
return (*hook)(bytes, RETURN_ADDRESS(0));
会寻找一个arena来试图分配内存
声明:
本文采用
BY-NC-SA
协议进行授权,如无注明均为原创,转载请注明转自
CyFin | Blog
本文地址: 初见heap
本文地址: 初见heap