📚 目录

  1. C/C++ 内存结构总览
  2. 栈(Stack)vs 堆(Heap)本质区别
  3. 全局区、常量区、代码区详解
  4. C语言内存分配函数:malloc / calloc / realloc / free
  5. C++内存运算符:new / delete 背后的秘密
  6. 对象模型:成员变量、虚函数表布局剖析
  7. 拷贝构造 / 赋值运算 / 析构完整内存生命周期
  8. 构造/析构顺序与内存布局(含继承、虚继承)
  9. 内存对齐、填充与 sizeof
  10. 自定义内存管理:内存池、operator new 重载
  11. 常见内存错误与调试技巧
  12. 总结:现代 C++ 内存安全利器(RAII、智能指针)

🧠 1. C/C++ 内存结构总览

程序运行时的内存五大区:

区域内容
栈区局部变量、函数参数、返回地址(自动释放)
堆区程序动态分配的内存,需要手动释放
全局区全局变量、静态变量(程序运行期间存在)
常量区字符串字面量、const 全局变量等
代码区存储可执行代码指令,函数体机器码

🧮 2. 栈 vs 堆

比较项
管理方式编译器自动管理程序员手动管理
生命周期离开作用域自动释放手动释放(free/delete
分配速度快(内存顺序增长)慢(维护空闲链表、碎片管理)
内存限制通常较小(如 1MB)受限于系统物理/虚拟内存

⚙️ 3. 全局区 / 常量区 / 代码区

const char* s1 = "hello"; // 存储在常量区
char s2[] = "hello";      // s2 本身在栈区,内容复制到栈上

字符串字面量共用,const 字符串不可修改!


🛠️ 4. C语言的内存分配函数

  • void* malloc(size_t size)
  • void* calloc(size_t count, size_t size):初始化为0
  • void* realloc(void* ptr, size_t new_size):扩容/收缩
  • void free(void* ptr)

💣 常见错误:

  • 忘记释放 malloc
  • free 释放未分配内存或释放两次

🔍 5. C++ 的 new/delete 背后机制

MyClass* p = new MyClass();   // 调用 operator new + 构造函数
delete p;                     // 调用析构函数 + operator delete

内部步骤:

  1. operator new 分配内存(底层是 malloc
  2. 调用构造函数
  3. delete:先调用析构,再释放内存(底层是 free

你可以自定义 operator new 和 delete

void* operator new(size_t size) {
    std::cout << "Custom new\n";
    return malloc(size);
}
void operator delete(void* p) {
    std::cout << "Custom delete\n";
    free(p);
}

🧩 6. C++ 对象模型与内存布局

示例:

class A {
    int a;
    virtual void f() {}
};

对象在内存中的布局如下:

  • 第一部分是 vptr:指向虚函数表(vtable)
  • 紧接着是成员变量(如 int a)

虚函数表是一个指针数组,存放指向虚函数的地址。


🔁 7. 拷贝构造、赋值运算、析构函数

class MyClass {
public:
    MyClass();                           // 构造
    MyClass(const MyClass& other);      // 拷贝构造
    MyClass& operator=(const MyClass&); // 赋值
    ~MyClass();                          // 析构
};

生命周期顺序:构造 → 拷贝 / 赋值 → 析构
构造/析构时机是管理资源(如内存、文件句柄)的关键。


🧱 8. 继承与内存布局:构造/析构顺序

class Base {
public:
    Base() { std::cout << "Base\n"; }
    virtual ~Base() { std::cout << "Destruct Base\n"; }
};

class Derived : public Base {
public:
    Derived() { std::cout << "Derived\n"; }
    ~Derived() { std::cout << "Destruct Derived\n"; }
};

构造顺序:Base → Derived
析构顺序:Derived → Base(虚析构 否则析构不完全)


📏 9. 内存对齐与 sizeof 填充

struct A {
    char c;
    int i;
};

实际 sizeof(A) 是 8,不是 5,因为 int 要求对齐(通常 4 字节),结构体要按最大对齐值对齐。

可使用 #pragma pack(1) 控制对齐,但可能影响性能。


🧰 10. 自定义内存池(Memory Pool)

用于高性能场景(游戏、数据库、嵌入式):

  • 减少频繁调用系统 malloc/free
  • 提前分配大块内存
  • 内部分页、块管理

适合:

  • 大量小对象(如实体组件、消息包)
  • 固定大小的对象分配(定长池)

🔍 11. 内存错误常见类型

类型示例
内存泄漏malloc 后未 free
悬空指针delete 后仍使用指针
越界访问数组越界
double free多次释放同一指针
use-after-free指针释放后再次使用
未初始化内存使用未设置初值就使用

工具推荐:

  • Valgrind:Linux 上常用
  • ASAN(Address Sanitizer):现代 C++ 编译器支持
  • Visual Studio Memory Leak Detection

🛡️ 12. RAII 与现代 C++ 内存安全

RAII(资源获取即初始化)核心思想:

构造时获取资源,析构时自动释放!

搭配智能指针使用:

  • std::unique_ptr<T>
  • std::shared_ptr<T>
  • std::weak_ptr<T>

无需手动 delete,资源自动回收。


📚 参考链接


需要我为这个主题做成视频脚本、教学PPT、工程实战代码,或者搭配内存图讲解都可以。是否继续深入如:虚函数表图解 + 内存池代码实现 + new/delete 重载实战?欢迎告诉我目标场景(面试、学习、项目优化)。