首先,了解一下C / C++的内存分布,C/C++中程序内存区域一共划分为六段:
- 内核空间:程序内存一般为4G,1G为内核空间这个区域用户不能读写,3G为用户空间时用户可以操作的;
- 栈:一般存储非静态局部变量,函数参数,返回值等,由上向下增长;
- 内存映射段:装在一个共享的动态内存库,用户可以使用系统接口创建共享内存,做进程间通信;
- 堆:用于保存动态内存分配的变量,如:malloc, new创建的变量都是保存在堆上,堆时自下而上存储;
- 数据段:保存全局数据,静态成员。如:static成员
- 代码段:可执行代码保存的地方,还有只读常量也保存在代码段,如:字符串常量。
C中的内存管理方式:
在C语言中,有一些库函数可以实现内存管理:
int* p1 = (int*) malloc (sizeof(int)*4);
//开辟4个int大小的空间,只开辟,不初始化
int* p2 = (int*) realloc(p1, sizeof(int)*10);
//将空间调整成10个int大小的空间,如果比原空间小,就在原空间基础上
//减小空间,如果比原空间大,判断后续空间是否足够,不足够就重新开辟空间,把原空间内存拷贝过去
//如果足够,就在原空间的基础上扩容空间
int* p3 = (int*) calloc(4, sizeof(int));
//开辟4个int空间,并按位初始化为0,即开辟空间同时初始化
free(p1);free(p2);free(p3);
//开辟的所有空间在用完之后必须释放,不然会导致内存泄漏
C++内存管理方式:
new / delete操作符在C++中进行开辟内存和释放内存的工作。
对于内置类型而言,new 和 delete 与malloc 和 free类似。
int* a = new int;
//申请一个int类型空间
int* b = new int(10);
//申请一个int类型空间,并初始化为10
int* c = new int[10];
//申请10个连续int类型空间
delete a, b;
delete[] c;
//释放连续空间
如果创建多维数组,就得一维一维创建,并且由最后创建的向第一个创建的依次释放,以二位数组为例:
int **array
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m];
for( int i=0; i<m; i++ )
{
array[i] = new int [n] ;
}
//释放
for( int i=0; i<m; i++ )
{
delete [] arrary[i];
}
delete [] array;
对于自定义类型而言,new会调用这个类的构造函数来创建对象,delete会调用这个类的析构函数来释放对象。
需要注的是在使用new[ ]创建连续多个对象的时候,类中必须有默认构造函数。
operator new 和 operator delete
operator new 和 operator delete是系统提供的全局函数,
new 和 delete的底层其实就是调用operator new 和 operator delete函数。
operator new 相当于一个封装好的malloc + 异常,实际上还是使用malloc开辟空间。
operator delete 相当于封装了free。
由此,可以看出若是使用 new 和 delete操作符,将其步骤层层深入相当于:
new -> operator new -> malloc + 异常 -> 构造函数(自定义类型)
delete -> 析构函数(自定义类型) -> operator delete -> free
不同的是,如果是自定义类型,new会先开辟空间然后调用构造函数初始化,delete会先调用析构函数清理资源,然后调用free释放空间。
new定位表达式
显示调用构造函数初始化空间,先申请空间再显示调用构造函数,常用与内存池配合使用。
new(地址) 类型 //前面需要已经开辟空间
这边就得提一下内存池,首先,内存池是什么?
内存池是一个对象池,我们使用内存对象之前,先申请分配一定数量的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存,当不需要此内存时,重新将此内存放入预分配的内存块中,下次继续使用,这样合理的分配回收内存使内存分配效率得到提升。
为什么会有内存池??
由于我们每次使用new申请的内存大小不定,频繁的申请就会产生大量的内存碎片,而且频繁的分配和释放内存会降低性能,因为对象的析构和构造都需要时间,
关于内存泄漏
内存泄漏就是一块内存不再使用了,却没有及时释放。系统失去了对这段内存的控制,造成内存的浪费。
内存泄漏分为两种:
- 堆内存泄漏
常见的就是使用 malloc new 等从堆中分配内存的时候,用完之后没有及时的free 或 delete。导致这部分空间无法再使用。 - 系统内存泄漏
程序使用系统分配的资源,比如:套接字,文件描述符,管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
如何避免和解决内存泄漏?
有良好的编程习惯,严谨的思维;采用RAII思想或者智能指针,使用内存泄漏检测工具。