1.C/C++内存分布
让我们先来看这样一段代码
int globalVar = 1; static int staticGlobalVar = 1; void Test() { static int staticVar = 1; int localVar = 1; int num1[10] = { 1, 2, 3, 4 }; char char2[] = "abcd"; const char* pChar3 = "abcd"; int* ptr1 = (int*)malloc(sizeof(int) * 4); int* ptr2 = (int*)calloc(4, sizeof(int)); int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4); free(ptr1); free(ptr3); }
你知道上述代码种的每个变量分别在内存种的什么区域吗?
说明
- 栈又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信
- 堆用于程序运行时动态内存分配,堆是可以上增长的
- 数据段–存储全局数据和静态数据
- 代码段–可执行的代码/只读常量
这里解释一下,为什么说栈是向下增长的,堆是向上增长的
在申请空间的时候,栈先申请的空间是高地址,后申请的空间是低地址,堆先申请的空间是低地址,后申请的是高地址,所以说栈是向下生长,堆是向上生长
看下面一段代码:
void Test_stack() { //在栈区开辟a,b两个变量,先开辟的变量地址高 int a = 10; int b = 20; cout << "&a=" << &a << endl; cout << "&b=" << &b << endl; //在堆区开辟aa和bb,先开辟的地址低 int* aa = (int*)malloc(sizeof(int) * 2); int* bb = (int*)malloc(sizeof(int) * 2); cout << "aa=" << aa << endl; cout << "bb=" << bb << endl; }
注意:在堆区先开辟的不一定就比后开辟的地址低,也有可能开辟的是之前释放的内存。
2.C语言中动态内存的管理方式
在C语言中,通过四个函数来管理动态内存的,分别是malloc,realloc,calloc,free
1.malloc
malloc函数在内存中开辟一块指定大小的连续地址空间,并返回该空间的首地址,如果开辟不成功就返回NULL
2.calloc
calloc函数的功能也是在内存中开辟一块指定大小的连续地址空间,并返回该空间的首地址,在开辟的过程中,可以给定每个字节的初始值,如果开辟不成功则返回NULL
3.realloc
realloc函数的功能是修改动态开辟的内存大小,并返回修改后的内存地址空间首地址。
4.free
free函数的功能是释放动态开辟的内存
更详细的内容请看下面这篇博客:【C语言进阶】动态内存管理_小张在努力写代码的博客-CSDN博客
3. C++中动态内存的管理
在C++中,同样可以使用C语言中提供的内存管理方式,但是对于某些情况下,开辟自定义类型时,使用malloc等函数会出现一些问题,所以在C++中,用了新的内存管理方式-----new和delete
1.new/delete操作内置类型
void Test_new_delete_Built() { //操作内置类型 //动态申请一个整型大小的空间 int* ptr1 = new int; //动态申请一个整型大小的空间,并初始化为10 int* ptr2 = new int(10); //动态申请10个整型大小的空间 int* ptr3 = new int[10]; //对于new申请的空间,使用delete释放 delete ptr1; delete ptr2; //对于new[]申请的空间,使用delete[]释放 delete[] ptr3; }
new和malloc的区别
对于malloc:开辟空间失败返回空指针
对于new:开辟空间失败直接抛异常,不需要检查返回值
2.new/delete操作自定义类型
new/delete和malloc/calloc/realloc/free的真正区别在于自定义类型
class A { public: A(int* a = nullptr) :_a(a) { cout << "A()" << this << endl; } ~A() { cout << "~A()" << this << endl; } private: int* _a; }; void Test_Custom() { cout << "malloc:" << endl; A* pA1 = (A*)malloc(sizeof(A)); cout << pA1 << endl; cout << "------------------------------" << endl; free(pA1); cout << "new:" << endl; A* pA2 = new A(); delete pA2; }
可以看到,new/delete和malloc等C语言接口的区别就是new和delete调用了自定义类型的默认构造函数和析构函数,而malloc等接口不会调用,只起了管理内存的作用。
总结:
1. 在对于内置类型的内存管理的时候,使用new/delete和malloc/calloc/realloc/free没有什么去区别
2. 在对于自定义类型的内存管理的时候,new做了开辟内存+调用默认构造函数,delete做了释放内存+调用析构函数
3. 使用new开辟的空间要使用delete释放,使用new[]开辟的空间要使用delete[]释放
4. 建议在C++中无论是内置类型还是自定义类型的申请和释放,尽量都使用new和delete