跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 内存管理:malloc 底层原理与实现

C++ 内存管理中 malloc 函数通过 brk/sbrk 和 mmap 系统调用实现。小内存使用 brk/sbrk 扩展堆,大内存使用 mmap。ptmalloc 作为内存池管理机制,将内存划分为 chunk 进行管理。chunk 包含大小、指针等字段,空闲时维护双向链表。分配时优先查找空闲链表,不足时扩展堆或 mmap。释放时标记空闲并合并相邻块,必要时归还操作系统。

CoderByte发布于 2026/3/20更新于 2026/7/2745 浏览
C++ 内存管理:malloc 底层原理与实现

一、内存布局

图 1:内存布局示意图(栈向下扩展,堆向上扩展)

由上图可知,栈至顶向下扩展,堆至底向上扩展。

二、brk(sbrk)和 mmap 函数

1. brk(sbrk)

在 Linux 系统中,malloc 底层主要通过 brk、sbrk 和 mmap 这几个系统调用来实现内存的分配和管理。

#include <unistd.h>

void *brk(const void *addr);
void *sbrk(intptr_t incr);

两者的作用是扩展 heap 的上界 brk。

  • brk():参数设置为新的 brk 上界地址,成功返回 0,失败返回 -1;如果 addr 大于当前的程序中断点,就会扩大数据段,分配新的内存;如果 addr 小于当前的程序中断点,就会缩小数据段,释放内存。
  • sbrk():参数为申请内存的大小,返回 heap 新的上界 brk 的地址;当 increment 为正数时,堆顶指针会向高地址移动,分配内存;当 increment 为负数时,堆顶指针会向低地址移动,释放内存。

2. mmap

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);

mmap() 进行内存分配(malloc)时一般使用后者,前者主要是进行文件映射。 mmap 分配内存比较直接,相对的开销也较大,释放也比较简单,通过 munmap 函数可以立即将内存归还给操作系统。

一般来说,当 malloc 申请的内存较小时,会使用 brk 或 sbrk 来扩展堆内存;而当申请的内存较大时(通常阈值为 128KB),会直接使用 mmap 在内存映射区申请内存。

但是,如果每次申请内存都调用这些接口的话,势必会影响系统的性能,并且也极容易产生内存碎片。所以 malloc 采用 ptmalloc(内存池管理机制)对内存的分配与回收进行管理。

3. ptmalloc

ptmalloc 会预先向操作系统申请一块内存供用户使用,当我们申请和释放内存的时候,ptmalloc 会将这些内存管理起来,并通过一些策略来判断是否将其回收给操作系统。

3.1 chunk(内存块基本结构)

在 ptmalloc 中,内存是由一个个 chunk 组成,每个 chunk 由结构体 malloc_chunk 进行描述:

struct malloc_chunk {
    INTERNAL_SIZE_T prev_size; // 前一个 chunk 的大小(如果前一个 chunk 是空闲的)
    INTERNAL_SIZE_T size;      // 当前 chunk 的大小,包括头部开销
    struct malloc_chunk *fd;   // 双向链表指针,指向下一个空闲 chunk(仅当 chunk 空闲时使用)
    struct malloc_chunk *bk;   // 双向链表指针,指向上一个空闲 chunk(仅当 chunk 空闲时使用)
    /* 当前的 chunk 存在于 large bins 中时使用 */
    struct malloc_chunk *fd_nextsize;
    /* 仅当 chunk 空闲时使用 */
    struct malloc_chunk *bk_nextsize;
};
  • prev_size:表示前一个空闲的 chunk 大小,如果前一个 chunk 不空闲,该字段无意义,prev_size 主要用于相邻空闲 chunk 的合并。
  • size:当前 chunk 的大小和一些其他信息,其中低三位(A,M,P)中记录包括前一个 chunk 是否在使用中,当前 chunk 是否是通过 mmap 获得的内存,当前 chunk 是否属于非主分配区。
  • fd 和 bk:这两兄弟只有当该 chunk 块空闲时才存在,其作用是用于将对应的空闲 chunk 块加入到空闲 chunk 块链表中进行管理。例如,当一个 chunk 被释放时,它会根据 size 字段中的信息找到前一个和后一个 chunk,判断它们是否空闲,如果空闲则进行合并,然后将合并后的 chunk 通过这两个指针插入到相应的空闲链表中。如果该 chunk 块被分配给了应用程序使用,那么这两个指针被当作应用程序的使用空间,不会浪费。
  • fd_nextsize 和 bk_nextsize:和 fd、bk 类似。

注意:当 chunk 为空时才有 fd、bk、fd_nextsize、bk_nextsize 四个指针,当 chunk 不为空,这四个指针的空间是直接交给用户使用的。

3.2 malloc 分配大体流程
  1. 搜索空闲链表:首先,ptmalloc 会在快速链表(fast bins)(小于 4 字节)、小链表(small bins)和大链表(large bins)中查找是否有合适大小的空闲 chunk。快速链表用于管理小且常用大小的 chunk,这些 chunk 在释放时不会与相邻的 chunk 合并,分配速度很快;小链表中的 chunk 大小固定且不超过 512 字节,按大小顺序排列;大链表中的 chunk 大小大于 512 字节。如果在这些链表中找到了合适的 chunk,就直接返回该 chunk 给用户。
  2. 扩展堆或使用 mmap:如果在空闲链表中没有找到合适的 chunk,ptmalloc 会尝试从堆顶的 top chunk 中分配内存。(top chunk 相当于分配区的顶部空闲内存)如果 top chunk 的大小足够,就从 top chunk 中分割出一块满足需求的内存返回给用户,剩余部分成为新的 top chunk;如果 top chunk 的大小不足,且申请的内存小于一定阈值(如 128KB),ptmalloc 会调用 sbrk 扩展堆内存,然后从新扩展的内存中分配;如果申请的内存大于阈值,ptmalloc 会使用 mmap 将内存放到 mmaped chunk 上,当释放 mmaped chunk 上的内存的时候会直接交还给操作系统。
  3. 大块拆分:当从大链表中找到一个大于请求大小的 chunk 时,ptmalloc 会将该 chunk 拆分成两部分,一部分满足请求大小返回给用户,另一部分作为剩余块(remainder chunk),根据其大小插入到合适的空闲链表中。
3.3 释放流程

当调用 free 释放内存时,ptmalloc 会执行以下操作:

  1. 标记为空闲:首先将释放的 chunk 标记为空闲状态,并根据 chunk 的大小和标志位判断是否需要与相邻的空闲 chunk 进行合并。
  2. 合并相邻空闲块:如果当前 chunk 的前一个和后一个 chunk 都是空闲的,ptmalloc 会将它们合并成一个大的 chunk,减少内存碎片。合并后的 chunk 会被插入到合适的空闲链表中。
  3. 缩小堆:如果释放的 chunk 与 top chunk 相邻,且合并后的 top chunk 足够大(超过一定阈值),ptmalloc 会调用 sbrk 缩小堆内存,将多余的内存归还给操作系统。

目录

  1. 一、内存布局
  2. 二、brk(sbrk)和 mmap 函数
  3. 1. brk(sbrk)
  4. 2. mmap
  5. 3. ptmalloc
  6. 3.1 chunk(内存块基本结构)
  7. 3.2 malloc 分配大体流程
  8. 3.3 释放流程
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AIHubMix:一个API Key调用所有大模型
  • LIO-SAM 算法在 Ubuntu 22.04 与 ROS2 Humble 下的仿真实现
  • OpenClaw v7.0.0 桌面版首发,支持本地 AI 自动化代理
  • Zabbix 分布式开源监控系统实战部署
  • Linux 信号机制:信号的产生、类型与捕获
  • 5 款免费 AIGC 检测工具推荐与降重方法
  • 数据结构:单链表的概念、结构与实现
  • Faze4开源六轴机械臂:低成本机器人解决方案
  • 大模型微调技术 LoRA 核心原理与实战面经总结
  • WebAssembly反编译技术:WABT wasm-decompile完全指南
  • Win10 系统关闭 Microsoft Copilot 弹窗的 6 种有效方案
  • Flutter eip55 库在鸿蒙系统的适配指南:以太坊地址校验
  • C++ 技术栈全景解析与最佳实践
  • OpenClaw 飞书机器人权限管理与安全配置
  • 安卓本地跑 Stable Diffusion 的开源工具
  • Linux 网络基础:局域网通信与数据封装详解
  • Vue+Node.js+ElementUI 学生创新项目管理系统架构与实现
  • C++ ODB ORM 框架使用指南
  • 分布式文件系统 HDFS 存储原理
  • MATLAB 实现基于 BFOA-DNN 的无人机三维路径规划

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online