heap concept
堆其实就是程序虚拟地址空间的一块连续的线性区域它由低地址向高地址方向增长。一般称管理堆的那部分程序为堆管理器堆管理器处于用户程序与内核中间。在内存分配与使用过程中Linux基本内存管理思想只有当真正访问一个地址的时候系统才会建立虚拟页面与物理页面的映射关系。虽然操作系统已经给程序分配了很大的一块内存但这块内存其实只是虚拟内存。只有当用户使用到相应的内存时系统才会通过缺页真正分配物理页面给用户使用。Ptmalloc2 主要是通过malloc/free函数来分配和释放内存块malloc 返回对应大小字节的内存块的指针也对一些异常情况进行了处理malloc(n)当 n 0 时返回当前系统允许的堆的最小内存块。当 n 为负数时size_t是无符号数所以程序会申请很大的内存空间但通常都会失败因为系统没有那么多的内存可以分配。free 函数会释放由 p 所指向的内存块。这个内存块有可能是malloc函数得到的也有可能是通过相关的函数realloc得到的。同样也对异常情况进行了处理free(p)当 p 为空指针时函数不执行任何操作。当 p 已经被释放之后再次释放会出现乱七八糟的效果其实就是double free。除了被禁用(mallopt)的情况下当释放很大的内存空间时程序会将这些内存空间还给系统以便于减小程序所使用的内存空间。分配背后的系统调用申请和释放内存时并不真正与系统交互背后的系统调用主要是(s)brk以及mmap、munmap函数。(s)brk初始时堆的起始地址start_brk以及堆的当前末尾brk指向同一地址。是否开启ASLR,两者的具体位置会有所不同不开start_brk以及brk会指向data/bss段的结尾。开启start_brk以及brk也会指向同一位置只是这个位置是在data/bss段结尾后的随机偏移处。在不同的上下文里“堆”的含义差别很大分两层来理解。第一层操作系统层面的“堆” (Heap Segment)这是从进程的虚拟内存布局角度来看的。是什么在 Linux 进程中内存被划分为不同的段Segment其中有一个区域叫“堆段Heap Segment”。它位于数据段BSS之后向高地址方向生长。管理者这个区域由操作系统内核管理通过brk和sbrk系统调用可以调整堆段的“顶部边界”即 program break。特点这是进程最早获得的动态内存区域。它是一段连续的虚拟地址空间。进程启动时堆段只有很小的初始大小随着程序不断申请内存堆段会逐渐扩大brk向上推。一句话总结操作系统层面的“堆”是进程虚拟地址空间中一块可以被程序动态扩充和收缩的连续内存区域通过brk/sbrk来管理。第二层内存分配器层面的“堆” (Heap)这是从ptmalloc2内存分配器的角度来看的。在 Glibc 中malloc管理的内存并不局限于操作系统的那个“堆段”。广义的堆在ptmalloc2的语境下“堆”是一个更广义的概念它指的是所有由内存分配器管理并提供给malloc使用的动态内存池。它包含两种来源主分配区main_arena的堆这直接对应操作系统层面的那个堆段通过brk/sbrk扩展。这就是我们传统意义上说的“堆”。非主分配区thread arena的堆这些是通过mmap系统调用从操作系统匿名映射来的内存区域。它们在虚拟地址空间中是独立的、不连续的并不在传统的“堆段”内。管理单位在ptmalloc2中这些不同来源的内存块被抽象成统一的heap_info结构来管理非主分配区的每个堆段都有一个heap_info头部。对于主分配区因为它只有一个堆段所以不需要heap_info结构。一句话总结ptmalloc2中的“堆”是内存分配器管理的“内存池”的泛称它可能来自brk堆段也可能来自mmap映射区域。第三层数据结构层面的“堆” (Chunk Top Chunk)更具体地说在ptmalloc2的源码和运行机制中“堆”还指代两个具体的数据结构实体Top Chunk每个 Arena分配区都有一个Top Chunk。它位于该 Arena 当前活跃堆段的最顶部最高地址处。它是该 Arena 的“最后储备金”。当所有空闲链表Bin都无法满足分配请求时malloc会从 Top Chunk 中直接切割内存返回。当 Top Chunk 空间不足时主分配区会通过brk扩展堆段非主分配区会通过mmap创建新的堆段从而获得新的 Top Chunk。Heap Segment堆段对于非主分配区每个通过mmap映射来的连续内存区域称为一个“堆段”。堆段的头部有一个heap_info结构记录了它的大小、属于哪个 Arena以及指向前一个堆段的指针。一个非主分配区可以有多个堆段它们通过heap_info中的prev指针链接成一条单向链表。三者关系图--------------------------------------------------------- | 进程虚拟地址空间 | --------------------------------------------------------- | 代码段 | 数据段 | 堆段 (brk) | 内存映射段 (mmap) | 栈段 | ------------------------------------------------------ | | | ▼ ▼ ▼ ----------- ----------- -------------- | main_arena| | thread_arena| | thread_arena| ----------- ----------- -------------- | | | ▼ ▼ ▼ ----------- ----------- ----------- | Top Chunk | | heap_info | | heap_info | | (brk堆段) | | (mmap堆段1)| | (mmap堆段2)| ----------- ----------- ----------- ▲ ▲ ▲ | | | └──────┬───────┴──────────────────┘ │ ▼ 所有堆段共同构成了 ptmalloc2 管理的“堆”终极一句总结“堆”在 Glibc 的语境下是一个层叠的概念从内核看它是通过brk管理的一段连续虚拟内存区域堆段。从分配器看它是main_arena的brk堆段和所有thread_arena的mmap堆段的总集合。从数据结构看它是每个 Arena 顶部的Top Chunk以及构成这些 Top Chunk 的多个heap_info堆段。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →