内存管理
C/C++中程序内存区域划分:
- 栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
- 堆用于程序运行时动态内存分配,堆是可以上增长的。
- 数据段–存储全局数据和静态数据。
- 代码段–可执行的代码/只读常量。
C++内存管理方式
一、通过new和delete来进行动态内存管理。
- new和delete不是函数,C++提供的新的操作符
- new/new[] 只需在其后跟空间类型,不需要传递字节数
- new 后跟的就是空间的类型,因此不需要强转
- new/new[]可以进行初始化
- new的结果不需要判空
- new申请单个内存空间是,默认是在堆上申请。
new和delete操作内置类型:
void test()
{
int* p1=new int ;//动态申请一个int类型的空间
int* p2=new int (10);//动态申请一个int类型的空间并初始化为10
int* p3=new int [10];//动态申请十个int 类型的空间
delete p1;
delete p2;
delete [] p3;
}
new和delete操作自定义类型:
class test
{
public:
test()
:a(0)
{}
~test()
{}
private:
int a=0;
};
int main()
{
test* p1=new test;
test* p2=new test[10];
delete p1;
delete [] p2;
return 0;
}
注意:申请自定义类型的空间时,先申请空间,还需调用构造函数。delete会调用析构函数。而malloc和calloc不会。所以new对应delete ;new[]对应delete[];一定要匹配使用。
如果没有匹配使用产生的后果:
(1)如果申请的是内置类型的空间,不会有影响。
(2)如果申请的是自定义类型的空间,就会崩溃。因为new会调用构造函数,free不会调用析构函数,导致类对象中的资源不会被销毁。
operator new和operator delete函数
operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
operator delete:该函数最终由free来释放空间。
new和delete的实现原理:
自定义类型:
new原理:
1.调用operator new函数申请空间。
2.在申请的空间上执行类的构造函数,完成对象的构造。
delete原理:
1.执行析构函数,完成对象中资源的清理。
2.调用operator delete 函数释对象的空间。
new T[N]:
1.调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请。
2. 在申请的空间上执行N次构造函数 。
delete []
1.在释放的对象空间上进行 N次析构函数。
2.调用operator delete[]释放空间。
内存泄漏
**什么是内存泄露:**内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会 导致响应越来越慢,最终卡死。
如何避免内存泄露:
- 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。
- 采用RAII思想或者智能指针来管理资源。
- 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。