C语言动态内存管理
1.C语言使用malloc/calloc/realloc/free进行动态内存管理。
2.
malloc/calloc/realloc
malloc函数原型: void *malloc(size_t size); //分配内存块(不会抛出异常)
功能: 在内存的动态存储区中分配一个size字节大小的内存块,返回一个指向该块开头的指针。若size的大小为0,则返回值取决于特定的库实现,但返回的指针不应被解除引用。
新分配的内存块内容不被初始化。
返回值: 申请成功时,返回指向由该功能分配的内存块的指针;申请失败时,返回空指针。
calloc函数原型: void *calloc(size_t num, size_t size); //分配并初始化内存块(不会抛出异常)
功能: calloc函数与malloc函数相似,不同的是calloc函数会将分配的内存块初始化为0。若size的大小为0,则返回值取决于特定的库实现,但返回的指针不应被解除引用。
返回值: 申请成功时,返回指向由该功能分配的内存块的指针;申请失败时,返回空指针。
realloc函数原型:void *realloc(void *ptr, size_t size); //重新分配内存块(不会抛出异常)
功能:更改ptr指向内存块的大小(将内存块移动到新位置)。即使将内存块移动到新位置,内存块的内容仍可保留到新旧内存的较小者。若是新的内存块较大,则新分配的部分内存值是不确定的。
在ptr为空指针的情况下,函数的功能就如同malloc。
(C90/C98)若size的值为0,则先前在ptr中分配的内存被解除分配,就像调用free函数,并返回一个空指针。
(C99/C11)若size的大小为0,则返回值取决于特定的库实现,但返回的指针不应被解除引用。
返回值:返回指向重新分配的内存块的指针,可能与ptr相同
或者新位置。
3.
free
free函数原型:void free(void *ptr); //释放分配内存块(不会抛出异常 )
功能:释放分配给malloc、calloc、realloc的内存块,使其再次可用于进一步分配。此函数不会更改ptr本身的值,因此ptr仍指向相同的位置(已无效)。
若ptr未指向由malloc、calloc、realloc申请的的内存块,则会导致未定义的行为。若ptr为空指针,则该函数不执行任何操作。
C++动态内存管理
1.
C++通过new和delete动态管理内存。
new/delete动态管理对象,new[]/delete[]动态管理对象数组。
注意:malloc/free、new/delete、new[]/delete[]一定要匹配使用,否则可能出现内存泄露甚至崩溃的问题.
2.
全局变量、全局静态变量、局部变量、局部静态变量之间的区别是什么?
1)全局变量、全局静态变量、局部静态变量存储在数据段上,局部变量存储在栈上。
2)字符串存储在代码段上,malloc/calloc/realloc/new申请的内存块(并非内存块的名称)存储在堆上。
3)栈又叫堆栈,存储非静态局部变量/函数参数/函数返回值等等,且栈是
向下增长的。
4)内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可以使用系统接口创建共享内存,作进程间通信。
5)堆存储程序运行时动态内存分配,且堆是向上增长的。
6)数据段存储全局数据和静态数据。
7)代码段存储可执行代码/只读常量。
3.
我们知道C++是兼容C的,那么已经有C库malloc/free等来动态管理内存,为什么C++还要定义new/delete运算符来动态管理内存?(malloc/free和new/delete的区别与联系)
1)malloc/free和new/delete都是动态管理内存的入口。
2)malloc/free是C/C++标准库的函数,new/delete是C++操作符。
3)malloc/free只是动态分配内存空间/释放空间,new/delete除了分配/释放内存还会调用构造函数和析构函数进行初始化与清理工作。
4)malloc/free需要手动计算类型大小且返回值为void *,new/delete可自己计算类型的大小且返回值为对应类型的指针。
4.
C++其他内存管理接口 (并没有重载new/delete表达式)
void *operator new(size_t size);
void operator delete(size_t size);
void *operator new[](size_t size);
void operator delete[](size_t size);
通过调用operator new函数执行new表达式获得内存,接着在该函数中构造一个对象。
通过撤销一个对象执行delete表达式,接着调用operator delete函数释放对象使用的内存。
总结:1)operator new、operator delete、operator new[]、operator delete[]与malloc/free用法一样。
2)只负责分配/释放空间,不会调用对象构造/析构函数来初始化/清理对象。
3)实际上operator new、operator delete只是malloc、free的一层封装。
5.
执行的操作
1)new做了两件事
调用operator new分配空间、调用构造函数初始化对象
2)delete做了两件事
调用析构函数清理对象、调用operator delete释放空间
3)new[N]做了两件事 (分配空间时会在空间的开始处多分配4个字节的大小,用于存储N,便于析构)
调用operator new分配空间、调用N次构造函数分别初始化每个对象
4)delete[N]做了两件事
调用N次析构函数清理对象、调用operator delete释放空间
6.
定位new表达式
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
new(place_address) type (place_address必须是一个指针)
new(place_address) type(initializer_list) (initializer_list是类型的初始化列表)
1)malloc/free + 定位操作符new()/显示调用析构函数,模拟new/delete行为
类名 *p = (类名 *)malloc(sizeof(类名));
new(p) 类名(初始值);
//new
p->类名的析构函数;
free(p);
//delete
2)malloc/free + 多次调用定位操作符new()/显示调用析构函数,模拟new[]/delete[]行为
类名 *p = (类名 *)malloc(sizeof(类名)* N);
for(i=0;i<N;i++)
{
new(p+i) 类名;
}
//new[N]
for(i=0;i<N;i++)
{
p[i].类名的析构函数;
}
free(p);
//delete[N]
7.
深度剖析new/delete与new[]/delete[]
1)new(size) -> operator new() -> malloc() -> 构造函数 -> ptr(返回值)
delete(ptr) -> 析构函数 -> operator delete() -> free()
2)new[count](size+4) -> operator new[]() -> operator new() -> malloc() -> 构造函数(count次) -> ptr(返回值)
delete[] -> 析构函数(count次) -> operator delete[]() -> operator delete() ->free()
(
new type[] type显示定义析构函数才会多开4个字节,以存储对象个数)