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

C/C++ 内存分布与动态管理实战指南

C/C++ 内存分布与动态管理机制详解。文章梳理了程序内存布局(代码段、数据段、堆、栈),对比了 C 语言 malloc/calloc/realloc 与 C++ new/delete 的操作差异。重点解析 realloc 扩容时的地址变化陷阱、operator new/delete 底层调用逻辑及构造函数析构函数的执行时机,为面试和实际开发提供清晰的内存安全实践指导。

PhpPioneer发布于 2026/3/22更新于 2026/10/1790 浏览
C/C++ 内存分布与动态管理实战指南

C/C++ 内存分布

在深入动态内存管理之前,先理清程序运行时的内存布局。下面这段代码展示了不同变量在内存中的位置:

#include <stdio.h>
#include <stdlib.h>

// 【全局/静态区】.data:已初始化的全局变量
int globalVar = 1;

// 【全局/静态区】.data:已初始化的静态全局变量(作用域限制在本文件)
static int staticGlobalVar = 1;

void Test() {
    // 【全局/静态区】.data:已初始化的静态局部变量(生命周期为整个程序)
    static int staticVar = 1;

    // 【栈区】:局部变量,函数运行结束自动释放
    int localVar = 1;

    // 【栈区】:局部数组
    int num1[10] = {1, 2, 3, 4};

    // 【栈区】:字符数组(注意:"abcd" 会被拷贝到栈上)
    char char2[] = "abcd";

    // 【指针在栈区】,但指向的 "abcd" 字符串字面量在【常量区/代码段】
    const char* pChar3 = "abcd";

    // 【指针在栈区】,指向【堆区】通过 malloc 分配的内存
    int* ptr1 = (int*)malloc(sizeof(int) * 4);

    // 【指针在栈区】,指向【堆区】通过 calloc 分配并初始化的内存
    int* ptr2 = (int*)(, ());

    
    * ptr3 = (*)(ptr2, () * );

    
    (ptr1);
    (ptr3);
}
calloc
4
sizeof
int
// 【指针在栈区】,将 ptr2 原有的【堆区】内存进行扩充/移动
int
int
realloc
sizeof
int
4
// 手动释放【堆区】内存
free
free

内存分布示意图

内存区域详解

C 语言的动态内存管理

C 语言主要通过 malloc、calloc、realloc 和 free 来操作堆内存。这里有两个面试中高频出现的考点。

realloc 的工作机制

void Test() {
    int* p2 = (int*)calloc(4, sizeof(int));
    int* p3 = (int*)realloc(p2, sizeof(int) * 10);
    free(p3);
}

问题:这里需要 free(p2) 吗?

不需要,甚至绝对不能这样做。

原因在于 realloc 的内部逻辑:如果扩容成功,它可能返回原地址,也可能因为内存碎片等原因搬迁到新地址。如果返回了新地址,原内存块(p2 指向的空间)会自动被系统回收。如果你手动执行 free(p2),会导致'重复释放'(Double Free),这通常会直接引发程序崩溃。

malloc/calloc/realloc 的区别

函数功能描述初始化行为参数形式
malloc分配指定字节大小的内存不初始化,内容为随机垃圾值malloc(size_t size)
calloc分配 n 个元素的内存自动初始化为 0calloc(n, size)
realloc调整已分配内存块的大小不对新增空间进行初始化realloc(ptr, new_size)

C++ 的动态内存管理

C++ 保留了 C 的内存管理方式,但引入了更高级的 new 和 delete 操作符。它们不仅负责分配内存,还涉及对象的构造与析构。

1. 操作内置类型

对于 int、double 等内置类型,new 和 delete 的使用相对直观。

单个变量的分配和释放
  • 分配: new 类型 或 new 类型 (初始值)
  • 释放: delete 指针变量
int main() {
    // 1. 分配一个未初始化的 int
    int* p1 = new int;
    
    // 2. 分配并初始化为 100
    int* p2 = new int(100);
    
    // 使用完毕后必须释放内存
    delete p1;
    delete p2;
    
    // 良好的习惯:将指针置为空,防止野指针
    p1 = nullptr;
    p2 = nullptr;
    
    return 0;
}
一维数组的分配与释放

处理数组时,必须使用方括号 [],否则会导致未定义行为。

  • 分配: new 类型 [元素个数]
  • 释放: delete[] 指针变量
void manageArray() {
    int size = 5;
    // 分配一个长度为 5 的 int 数组
    int* arr = new int[size];
    
    // 初始化数组
    for (int i = 0; i < size; ++i) {
        arr[i] = i * 10;
    }
    
    // 释放数组内存
    delete[] arr;
}

2. 操作自定义类型

对于 struct 或 class,new 和 delete 的核心差异在于它们会调用构造函数和析构函数。

#include <iostream>
using namespace std;

class A {
public:
    A(int a = 0) : _a(a) { cout << "A():" << this << endl; }
    ~A() { cout << "~A():" << this << endl; }
private:
    int _a;
};

int main() {
    // 仅分配内存,不调用构造函数
    A* p1 = (A*)operator new(sizeof(A));
    // 分配内存并调用构造函数
    A* p2 = new A(1);
    
    operator delete(p1); // 仅释放内存
    delete p2;           // 先析构再释放内存
    
    int* p3 = (int*)operator new(sizeof(int));
    int* p4 = new int;
    operator delete(p3);
    delete p4;
    
    A* p5 = (A*)operator new(sizeof(A) * 10);
    A* p6 = new A[10];
    operator delete[](p5);
    delete[] p6;
    
    return 0;
}

3. operator new 与 operator delete 函数

new 和 delete 是操作符,而 operator new 和 operator delete 是底层的全局函数。

  • new 表达式 (new Type()): 全自动过程。
    1. 调用 operator new 分配原始内存。
    2. 调用构造函数初始化对象。
  • operator new (函数): 类似于 malloc,只负责分配原始内存,不负责构造对象。
operator new 详解
  • 原型: void* operator new(size_t size);
  • 工作原理:
    • 参数: size 是需要分配的字节数。
    • 返回值: 指向分配内存起始地址的 void* 指针。
    • 失败处理: 默认情况下,如果分配失败,抛出 std::bad_alloc 异常,而不是返回 nullptr。
    • 自定义行为: 可以重载该函数来实现内存池或审计逻辑。
operator delete 详解
  • 原型: void operator delete(void* ptr) noexcept;
  • 工作原理:
    • 对应关系: delete 表达式会先调用析构函数,然后调用 operator delete 释放内存。
    • 安全性: 向 operator delete 传递 nullptr 是安全的,函数会直接返回。
    • 底层实现: 通常封装了 free() 或系统底层的内存回收接口。

注:noexcept 表示该函数保证不会抛出异常。

通过上述分析可知,operator new 实际也是通过 malloc 来申请空间,如果 malloc 成功则返回,否则执行用户提供的应对措施或抛异常;operator delete 最终是通过 free 来释放空间的。

4. new 和 delete 的实现原理

内置类型

对于内置类型,new/delete 与 malloc/free 基本类似。区别在于:

  • new/delete 申请的是单个元素的空间,new[]/delete[] 申请连续空间。
  • new 失败抛异常,malloc 返回 NULL。
自定义类型
  • new 的原理:
    1. 调用 operator new 函数申请空间。
    2. 在申请的空间上执行构造函数。
  • delete 的原理:
    1. 在空间上执行析构函数。
    2. 调用 operator delete 函数释放空间。
  • new T[N] 的原理:
    1. 调用 operator new[] 函数完成 N 个对象空间的申请。
    2. 执行 N 次构造函数。
  • delete[] 的原理:
    1. 执行 N 次析构函数。
    2. 调用 operator delete[] 释放空间。

5. malloc/free 和 new/delete 的区别

两者的共同点是从堆上申请空间且需手动释放。主要区别如下:

  1. 本质不同: malloc/free 是函数,new/delete 是操作符。
  2. 初始化: malloc 不初始化,new 可以初始化。
  3. 参数: malloc 需手动计算字节大小,new 只需跟类型,数组可用 [] 指定个数。
  4. 返回值: malloc 返回 void* 需强转,new 返回具体类型指针。
  5. 错误处理: malloc 失败返回 NULL,需判空;new 失败抛异常,需捕获。
  6. 对象生命周期: malloc/free 只管理内存,不调用构造/析构函数;new/delete 会完整管理对象的生命周期。

目录

  1. C/C++ 内存分布
  2. C 语言的动态内存管理
  3. realloc 的工作机制
  4. malloc/calloc/realloc 的区别
  5. C++ 的动态内存管理
  6. 1. 操作内置类型
  7. 单个变量的分配和释放
  8. 一维数组的分配与释放
  9. 2. 操作自定义类型
  10. 3. operator new 与 operator delete 函数
  11. operator new 详解
  12. operator delete 详解
  13. 4. new 和 delete 的实现原理
  14. 内置类型
  15. 自定义类型
  16. 5. malloc/free 和 new/delete 的区别

更多推荐文章

查看全部
  • AI 绘画模型下载优化指南:10 个高效解决方案
  • Python 真实世界数据科学:回归分析预测连续目标变量
  • C++ 输入输出详解(上):基础流与格式控制
  • 基于 OpenClaw 与 Claude 的自动化写作工作流实践
  • GitHub 版本控制实战:从零开始掌握核心技巧
  • 技术拆解:P2P 组网实现远程 AI 服务安全访问
  • vLLM + Open-WebUI 部署通义千问 2.5-7B 完整教程
  • 无监督学习:原理、算法与结构发现
  • 基于 SpringBoot+Vue 的网上摄影工作室管理系统设计与实现
  • 基于 LangChain 的 ReAct AI Agent 搭建实战
  • 深入理解 Transformer 架构:从注意力机制到位置编码
  • Python 网络副业常见方向与实战指南
  • AgentScope-Java 配置参数详解附录 B
  • Prompt Engineering 提示工程从入门到精通指南
  • 基于 SpringBoot+Vue3+MyBatis 的 MES 生产制造执行系统设计
  • 前端实现 Word 文档在线编辑与导出:基于 mammoth.js 与 Blob 对象
  • WebRTC 架构全景解析:从浏览器 API 到 libwebrtc
  • 基于 Coze 构建专属 AI 应用:从智能体到 Web 部署
  • C++ 继承机制详解:从基础概念到多继承实战
  • Windows 23H2 Copilot 关闭方案:任务栏隐藏与注册表禁用

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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