🔥铅笔小新z:个人主页
🎬博客专栏:C++学习
💫滴水不绝,可穿石;步履不休,能至渊。
C/C++ 内存管理详解:从入门到面试必备
大家好!今天我们来聊聊 C/C++ 中的内存管理,这是一个初学者容易迷糊、面试官又特别喜欢问的话题。内存管理理解好了,不仅能写出更稳定、更高效的程序,还能在面试中脱颖而出。我会尽量用大白话讲清楚,咱们一步步来。
一、C/C++ 程序的内存布局
我们先来看一个例子:
intglobalVar=1;// 全局变量staticintstaticGlobalVar=1;// 静态全局变量voidTest(){staticintstaticVar=1;// 静态局部变量intlocalVar=1;// 局部变量intnum1[10]={1,2,3,4};// 局部数组charchar2[]="abcd";// 局部字符数组constchar*pchar3="abcd";// 常量字符串指针int*ptr1=(int*)malloc(4*sizeof(int));// 动态分配}这些变量分别存在哪里呢?
globalVar、staticGlobalVar、staticVar→数据段(静态区)localVar、num1、char2→栈"abcd"(常量字符串) →代码段(常量区)ptr1(指针变量本身) →栈*ptr1(指向的内存) →堆
内存区域划分(图解)
高地址 → 内核空间(用户不可见) ↓ 栈(向下增长,存放局部变量、函数参数等) ↓ 内存映射段(文件映射、动态库、共享内存) ↓ 堆(向上增长,动态分配内存) ↓ 数据段(存放全局变量、静态变量) ↓ 低地址 → 代码段(存放可执行代码、常量)二、C 语言动态内存管理:malloc / calloc / realloc / free
C 语言中动态内存管理靠这四个函数:
malloc(size):申请指定字节的内存,不初始化。calloc(num, size):申请num个大小为size的内存,并初始化为 0。realloc(ptr, size):调整已分配内存块的大小(可扩大或缩小)。free(ptr):释放内存。
面试常问:
malloc / calloc / realloc 的区别?
答:
malloc只分配,不初始化;calloc分配并清零;realloc调整已有内存块大小,可能移动数据。
malloc 的实现原理?
答:glibc 中的malloc使用brk / sbrk或mmap系统调用来管理内存,内部维护一个内存池和空闲链表,减少系统调用次数,提高分配效率。
三、C++ 内存管理:new / delete
C++ 引入了new和delete来更方便地管理内存,尤其是对于自定义类型。
int*p1=newint;// 申请一个 intint*p2=newint(10);// 申请并初始化为 10int*p3=newint[10];// 申请 10 个 int 的数组deletep1;deletep2;delete[]p3;// 注意:数组用 delete[]与 malloc / free 的最大区别:
new会调用构造函数,delete会调用析构函数。malloc/free只负责内存分配和释放,不调用构造/析构。
classA{public:A(){cout<<"构造\n";}~A(){cout<<"析构\n";}};A*p1=(A*)malloc(sizeof(A));// 不调用构造A*p2=newA;// 调用构造free(p1);// 不调用析构deletep2;// 调用析构四、operator new 与 operator delete
这两个是 C++ 内置的全局函数,new和delete底层就是调用它们:
operator new内部调用malloc,失败时抛出bad_alloc异常。operator delete内部调用free。
你可以重载它们,实现自定义内存管理(比如内存池)。
五、new / delete 的实现原理
1. 内置类型
和malloc/free差不多,只是多了异常处理。
2. 自定义类型
new:- 调用
operator new分配内存 - 调用构造函数初始化对象
- 调用
delete:- 调用析构函数清理资源
- 调用
operator delete释放内存
六、定位 new(placement-new)
如果你已经有一块内存(比如从内存池来的),想在这块内存上构造对象,可以用定位 new:
A*p=(A*)malloc(sizeof(A));new(p)A();// 在 p 指向的内存上调用构造函数p->~A();// 显式调用析构free(p);常见用途:内存池、高性能内存管理。
七、malloc/free 与 new/delete 的区别(面试必背)
| 特性 | malloc / free | new / delete |
|---|---|---|
| 类型 | 函数 | 操作符 |
| 初始化 | 不初始化 | 可初始化 |
| 大小计算 | 需手动计算 | 自动计算 |
| 返回值 | void*,需强转 | 自动匹配类型 |
| 失败处理 | 返回 NULL | 抛出异常 |
| 构造/析构 | 不调用 | 调用 |
| 适用对象 | 内置类型 | 内置+自定义类型 |
八、常见面试题扩展
内存泄漏怎么办?
使用智能指针(unique_ptr、shared_ptr)、RAII 机制,或工具如 Valgrind 检测。什么是浅拷贝和深拷贝?
浅拷贝只拷贝指针,深拷贝会拷贝指针指向的内容。动态内存必须深拷贝。什么是内存对齐?
计算机为了高效读写内存,要求数据地址是其大小的整数倍。#pragma pack可控制对齐方式。
九、总结
C/C++ 内存管理是编程基本功,理解清楚:
- 内存布局:栈、堆、数据段、代码段
- C 方式:malloc / calloc / realloc / free
- C++ 方式:new / delete,支持构造析构
- 区别:malloc 是函数,new 是操作符;new 会初始化、抛异常、调构造
- 高级话题:operator new、定位 new、内存池
掌握这些,你不仅能写出更安全的代码,还能在面试中游刃有余。
如果这篇文章对你有帮助,欢迎点赞、收藏、转发!我们下期再见!
作者:铅笔小新z
日期:2025 年 12 月 2 日