美文网首页
理解Linux堆内存管理

理解Linux堆内存管理

作者: 梦工厂 | 来源:发表于2020-10-11 19:54 被阅读0次

一、堆的基础知识

1.1 堆的内存布局

1.2 堆和栈的区别
  • 栈主要用来维护函数调用的上下文,由高向低增长;
  • 堆用来容纳程序动态分配的内存区域,使用malloc或new分配的内存,由低向高增长;

二、堆的实现原理

2.1 malloc底层的系统调用

Syscalls used by malloc. (代码演示虚拟空间的变化)

  1. brk: brk obtains memory (non zero initialized) from kernel by increasing program break location (brk). Initially start (start_brk) and end of heap segment (brk) would point to same location.
    向上增长
  2. mmap: malloc uses mmap to create a private anonymous mapping segment. The primary purpose of private anonymous mapping is to allocate new memory (zero filled) and this new memory would be exclusively used by calling process.
    向下增长

2.2 malloc 实现原理

资料

  1. Understanding glibc malloc
  2. Linux 堆内存管理深入分析(上) Linux堆内存管理深入分析(下) (对上文的翻译和扩充)

多线程的支持
原来Linux的内存管理是dlmalloc,两个线程同时请求malloc只有一个能进入临界区;
后来被支持多线程的ptmalloc2代替,两个线程可以同时分别分配内存;

数据结构
  1. Arena

    • 一块连续的堆内存叫做arena,负责提供线程的内存分配和回收。
    • 主线程创建的arena叫做main arena,通过brk方式;
      其他线程创建的arena叫做thread arena,通过mmap方式;
      用户请求大于128KB时,来自main arena还是thread arena,都通过mmap的方式分配空间。
    • 线程和arena不是一一对应,存在数量限制所以会共享
      For [32 bit] systems: Number of arena = 2 * number of cores + 1.
      For [64 bit] systems: Number of arena = 8 * number of cores + 1.
  2. Heap

    • main arena中只有一个heap,内存不够时通过brk方式扩展,知道碰到内存映射段;
      thread arena中存在多个heap,内存不够时通过mmap方式新建heap,heap之间非连续,通过Heap Header管理;
    • 每个heap的基本单位是chunk,内存分配的单位也是chunk;
    • 每个arena可以有多个heap,但heap只是提供了物理空间,真正管理chunk的结构是bins, top chunk, last remainder chunk;


      只有一个heap
      多个heap
  3. chunk

    • 堆实际是连续的、大小不一的chunk组成,可以分为Allocated chunk、Free chunk、Top chunk、Last Remainder chunk四类;
    • chunk的结构比较有意思
      • size:自己的Size,因为是连续空间,根据自己的size加上偏移就是下一个chunk;
      • prev_size:上一个chunk的size,和前一个chunk合并是困难的,但是保存了prev_size,连续空间就可以计算出前一个chunk的位置;
      • PREV_INUSE (P) – This bit is set when previous chunk is allocated.
        IS_MMAPPED (M) – This bit is set when chunk is mmap’d.
        NON_MAIN_ARENA (N) – This bit is set when this chunk belongs to a thread arena.
      • 物理上chunk在heap中连续,但同一类chunk的管理是通过bins结构。fd、bk分别Points to next chunk in the same bin (and NOT to the next chunk present in physical memory).
       chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |             Size of previous chunk, if allocated            | |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |             Size of chunk, in bytes                       |M|P|
         mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |             User data starts here...                          .
           .                                                               .
           .             (malloc_usable_size() bytes)                      .
           .                                                               |
       nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |             Size of chunk                                     |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      
  4. Bins
    Bins是用来维护free chunk的链表数据结构,分配chunk从bins选,释放的chunk添加到bins;
    Bins分为了四类:Fast bin、Unsorted bin、Small bin、Large bin;

    • Fast bin

      • Chunks of size 16 to 80 bytes is called a fast chunk,一个Fast bin就是一个fast chunk的链表。
      • 一共10个Fast bin,Fast bin1存储16字节的fast chunk,Fast bin2存储24字节的fast chunk,so on (16-80字节)。
      • fast chunk的特点是两个相邻的fast chunk不需要合并,所以free非常快。
      • fast chunk的maloc和free都是在对应的fast bin的链表头增加和删除,LIFO;


    • Unsorted bin
      当 small or large chunk被free的时候不会直接加入到相应的small bin和large bin中,而是被添加到Unsorted bin;主要的目的是为了重新利用这些刚被释放的chunk;

      • unsorted bin只有一个,是一个由free chunks组成的循环双链表;
      • 在unsorted bin中,对chunk的大小并没有限制,任何大小的chunk都可以归属到unsorted bin中;
    • Small bin
      小于512字节的chunk称之为small chunk,small bin就是用于管理small chunk的。就内存的分配和释放速度而言,small bin比larger bin快,但比fast bin慢。

      • small bin有62个,每个small bin都是free chunk的双向链表,FIFO;
      • 每个small bin中的chunk大小是一样的,不同的small bin从16字节开始,步长为8字节,直到512字节;
      • malloc:找到匹配的非空bin,返回最后一个chunk;
        free:当释放small chunk的时候,先检查该chunk相邻的chunk是否为free,如果是的话就进行合并操作:将这些chunks合并成新的chunk,然后将它们从small bin中移除,最后将新的chunk添加到unsorted bin中。
    • Large bin
      大于512字节的chunk称之为large chunk,large bin就是用于管理这些large chunk的。large chunk最慢,因为一个Large bin中不同的chunk可以不一样大。

      • large bin有63个,双向链表,删除和添加的位置不在头尾,可以任意位置;
      • 步长不一样,在这63个large bins中,前32个large bin依次以64字节步长为间隔,即第一个large bin中chunk size为512~575字节,第二个large bin中chunk size为576 ~ 639字节。紧随其后的16个large bin依次以512字节步长为间隔;之后的8个bin以步长4096为间隔;再之后的4个bin以32768字节为间隔;之后的2个bin以262144字节为间隔;剩下的chunk就放在最后一个large bin中。
      • 一个 large bin中的large chunk按照大小倒序排列。
      • malloc(large chunk)操作:初始化完成之前的操作类似于small bin,这里主要讨论large bins初始化完成之后的操作。首先确定用户请求的大小属于哪一个large bin,然后判断该large bin中最大的chunk的size是否大于用户请求的size(只需要对比链表中front end的size即可)。如果大于,就从rear end开始遍历该large bin,找到第一个size相等或接近的chunk,分配给用户。如果该chunk大于用户请求的size的话,就将该chunk拆分为两个chunk:前者返回给用户,且size等同于用户请求的size;剩余的部分做为一个新的chunk添加到unsorted bin中
      • Free(large chunk):类似于small chunk。
  5. Top chunk
    每个arena的最高区域的chunk就是Top chunk,只有一个,不属于任何的bin。当系统的哪类bin都没有满足用户请求的free chunk时就需要用到Top chunk了。

    • 当Top chunk大于用户请求,一分为二。 User chunk和剩余的chunk,该chunk也就变成了新的Top chunk;
    • 当Top chunk小于用户请求,就需要扩展heap(main arena使用brk)或者分配新的heap(thread arena使用mmap)。
内存分配的过程

首先是fast bin,其次是small bin,然后是unsorted bin,最后是large bin。

三、后续学习

相比于之前对于堆只有个概念上的了解,现在对于堆的内存管理有了更直观的认识,
下一步有时间还是得深入源码来分析内存分配和回收的具体实现。

相关文章

  • 理解Linux堆内存管理

    一、堆的基础知识 1.1 堆的内存布局 1.2 堆和栈的区别 栈主要用来维护函数调用的上下文,由高向低增长; 堆用...

  • 2. 托管内存

    对于Unity内存管理而言,需要理解托管堆。对于如何分析托管内存和如何优化内存,可以参见Unity优化中的理解托管...

  • linux驱动之内存使用

    一、前言 在 Linux设备驱动 中,内存使用 是一个逃不掉的话题。Linux内核 的内存管理庞大且复杂,要想理解...

  • 从源码角度看Golang的堆内存管理

    从源码角度看Golang的堆内存管理 本章主要从源码角度针对Go堆上的内存管理进行分析。仅关注linux系统下的逻...

  • 基本知识摘录

    一:内存管理的理解首先iOS中数据是存贮在堆和栈中的。内存管理需要管理堆上的内存,栈上的内存并不需要我们管理。非O...

  • Linux内存管理---伙伴堆算法(1)

    什么是伙伴堆算法 伙伴堆算法(也叫伙伴系统,buddy system)是Linux系统中的一种动态的内存管理算法 ...

  • 系统启动及故障排错和内核管理

    (一)Linux组成结构 Linux: kernel+rootfskernel: 进程管理、内存管理、网络管理、...

  • 7. heaptrack

    linux的堆内堆内存分析器 1. github heaptrack

  • 第10章 内存管理和文件操作

    1 内存管理 1.1 内存管理基础 标准内存管理函数堆管理函数虚拟内存管理函数内存映射文件函数 GlobalMem...

  • 7、内存

    本节内容比较简单,主要介绍了栈与调用管理,并简单说明了程序的内存布局和堆的管理方式,对于一个linux进程的内存布...

网友评论

      本文标题:理解Linux堆内存管理

      本文链接:https://www.haomeiwen.com/subject/zzwuuktx.html