文章目录
前言
(本文为个人学习时的笔记和部分个人思想,如有理解误区或者知识点的缺少还请麻烦指出哦)
一、C/C++内存分布
1.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);
}
看以上代码来思考回答以下问题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?__C__ staticGlobalVar在哪里?__C__
staticVar在哪里?__C__ localVar在哪里?__A__
num1 在哪里?__A__
char2在哪里?__A__ *char2在哪里?_A__
pChar3在哪里?__A__ *pChar3在哪里?__D__
ptr1在哪里?_A___ *ptr1在哪里?__B__
-
globalVar和staticGlobalVar、staticVar都是存再内存空间中的静态区中。(作用域不一样但是他们的生命周期都是一样的)
-
localVar和num、char2因为都是函数内的变量所以都是存储在内存空间中栈的部分。
-
char 2是存在栈空间里,char 2这段代码会在栈空间开辟五个字节存放’a,b,c,d,\0’,而char 2是数组名,数组名是这个空间的首元素地址。所以cahr 2是第一个元素的地址。在栈空间。
-
Pchar3也是一样都是变量名都存放在栈空间,*Pchar3存放在代码段(常量区)。注意这里Pchar3和char2是不一样的,char2 [ ]是在栈空间开辟的空间,而 const char pChar3是用存在常量区的“abcd”在给它赋值。且Pcahr3的字符串数组是不能被修改的。
-
ptr1是指针变量名,变量名都是放在栈空间上。不过ptr1指向的空间是malloc出来的。ptr 1是它开辟出来的空间,所以ptr 1指向的是堆空间
我们看下图来具体体会他们在内存中存放的位置。
内存分区:
- 栈 –
存放非静态变量/函数参数/返回值
等,地址由下增长。 - 内存映射段(共享区),用于装载一个共享的动态内存库,让用户可以使用系统接口创建共享内存。用于进程之间通讯。(等我滴Linux博客补到这里再细说)
- 堆 – 用于程序运行时动态内存分配,堆是可以上增长的。(比如malloc等创建出来的空间出来的空间)
- 数据段–存储全局数据和静态数据。
- 代码段 – 存放我们可以执行的代码和只读常量。
二、C/C++中动态内存管理方式
1.C语言内存管理malloc/realloc/calloc的区别
他们的区别:
malloc是在堆中开辟了一块空间
,calloc在malloc的基础上把内部空间初始化为0。
realloc是在一块空间的基础上扩容,也可以直接开辟一块空间,需要注意的是如果realloc时如果物理上它后面的内存放不下需要扩容的空间,realloc就会再选择一块空间扩容。
需不需要free(pc):
这里不用free(pc),这里如果realloc正常扩容的话pc和pr指向的是同一块空间,如果realloc异地扩容的话它原本指向的空间就会被释放掉(pc会自动被free掉)。
2.C++内存管理
2.1new/delete操作内置类型
在C++中更新了新的内存管理操作符:new和delete
new和delete在操作内置类型时和malloc/free都是有着同样的功能。
不过更为简洁方便。
注意:new/delete和malloc/free最好不要交叉混用
这里初始化多个空间时想要同时初始化在“ [ ] ”后加上“ { } ”作为初始化值。
2.2 new/delete操作自定义类型
new/delete和malloc/free的最大区别就是在自定义类型这里前者会自动调用构造函数和析构函数
。后者需要手动初始化和清理空间。
2.3 new A[ ] 和 delete[ ] A(了解)
我们来看以下代码:
这里无论使用free和delete都会造成报错。
只能使用delete [ ] 才不会报错。
为什么呢?(注意这里每个编译器实现机制不同)
所以还是最好要匹配使用
int main()
{
A* p1 = new A[10];
//free(p1);
//delete p1;
delete[] p1;
return 0;
}
2.4malloc/free和new/delete的区别(按自己理解记忆)
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:
- malloc和free是函数,new和delete是操作符
- malloc申请的空间不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个
对象,[]中指定对象个数即可 - malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
- malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
- 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间
后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
三、 operator new与operator delete函数(重点理解)
new和delete
是用户进行动态内存申请和释放的操作符,operator new 和operator delete
是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
-
operator new 底层是调用malloc实现的,如果当malloc内存申请失败时,operator new会抛异常。
-
operator delete会检测是否出现越界,最终还是相当于调用free
四、定位new
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new (place_address) type或者new (place_address) type(initializer-list)
place_address是一个开辟好的内存空间指针(还没有调用构造函数初始化),initializer-list是类型的初始化列表
int main()
{
// p1现在指向的只不过是与A对象相同大小的一段空间,
//还不能算是一个对象,因为构造函数没有执行
A* p1 = (A*)malloc(sizeof(A));
new(p1)A; // 注意:如果A类的构造函数有参数时,此处需要传参
p1->~A();
free(p1);
A* p2 = (A*)operator new(sizeof(A));
new(p2)A(10);
p2->~A();
operator delete(p2);
return 0;
}
五、内存泄漏
1.什么是内存泄漏,内存泄漏的危害。
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。