最近打了天津市赛和长城杯,遇到了好多堆题,也确实要走出舒适区了,但是没想到一上来给自己放了个大的。

堆和栈都是一种数据结构,但是并不像我们平时做的栈题,堆题的思路一般是从堆的创建销毁入手的,而栈一般都是程序创建好的,个别情况需要我们自己构建栈(这个另说)。堆和栈在程序中都是线性存储数据的,和算法里面的堆还不太一样(目前看来)。栈是从高地址向低地址伸展,而堆是从低地址向高地址伸展。栈一般都在函数的运行空间里,而堆一般都在程序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来试图分配内存

说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...