C语言动态内存管理
C语言使用malloc/calloc/realloc/free进行动态内存管理。
void Test ()
{
int* p1 = (int*) malloc (sizeof (int)*4);
free(p1 );
// 1.calloc/realloc/malloc 的区别是什么?
int* p2 = (int*) calloc(4, sizeof (int));
int* p3 = (int*) realloc(p2 , sizeof( int)*6);
// 这里需要free(p2)吗?
free(p2 );
free(p3 );
}
C++动态内存管理
C++通过new和delete动态管理内存。
new/delete动态管理对象。
new[]/delete[]动态管理对象数组。
void Test ()
{
int* p4 = new int; // 动态分配4个字节(1个 int)的空间单个数据
int* p5 = new int(3); // 动态分配4个字节(1个 int)的空间并初始化为3
int* p6 = new int[3]; // 动态分配12个字节(3个 int)的空间
delete p4 ;
delete p5 ;
delete[] p6 ;
}
注意malloc/free、new/delete、new[]/delete[]
一定匹配使用,一定匹配使用,一定匹配使用!!!重要的事说三遍!否则可能出现内存泄露甚至崩溃的问题
void Test ()
{
// 以下代码没有匹配使用,会发生什么?有内存泄露吗?会崩溃吗?
int* p4 = new int;
int* p5 = new int(3);
int* p6 = new int[3];
int* p7 = (int*) malloc(sizeof (int));
delete[] p4 ;
delete p5 ;
free(p5 );
delete p6 ;
delete p7 ;
}
内存管理
int globalVar = 1;
static int staticGlobalVar = 1;
void Test ()
{
// 1.全局变量、全局静态变量、局部静态变量、局部变量之间的区别是什么?
static int staticVar = 1;
int localVar = 1;
// 2.下面的a1和 a2和a3 有什么区别和联系?
int a1 [10] = {1, 2, 3, 4};
char a2 [] = "abcd";
char* a3 = "abcd";
int * p1 = ( int*) malloc (sizeof ( int)*4);
int * p2 = ( int*) calloc (4, sizeof ( int));
int * p3 = ( int*) realloc (p2 , sizeof( int )*4);
free (p1 );
free (p3 );
int * p4 = new int;
int * p5 = new int(3);
int * p6 = new int[3];
delete p4 ;
delete p5 ;
delete [] p6 ;
}
栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。
内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(现在只需要了解一下)
堆用于程序运行时动态内存分配,堆是可以上增长的。
数据段--存储全局数据和静态数据。
代码段--可执行的代码/只读常量。
【思考】
我们知道C++是兼容C的,那么已经有C库malloc/free等来动态管理内存,为什么C++还要定义new/delete运算符来动态管理内存?
深入理解C++动态内存管理
【malloc/free和new/delete的区别和联系?】
它们都是动态管理内存的入口。
malloc/free是C/C++标准库的函数,new/delete是C++操作符。
malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员)。
malloc/free需要手动计算类型大小且返回值会void*,new/delete可自己计算类型的大小,返回对应类型的指针。
class Array
{
public :
Array (size_t size = 10)
: _size(size )
, _a(0)
{
cout<<"Array(size_t size)" <<endl;
if (_size > 0)
{
_a = new int[ size];
}
}
~ Array()
{
cout<<"~Array()" <<endl;
if (_a )
{
delete[] _a ;
_a = 0;
_size = 0;
}
}
private :
int*_a ;
size_t _size ;
};
void Test ()
{
Array* p1 = (Array*) malloc(sizeof (Array));
Array* p2 = new Array;
Array* p3 = new Array(20);
Array* p4 = new Array[10];
free(p1 );
delete p2 ;
delete p3 ;
delete[] p4 ;
}
C++的其他内存管理接口(placement版本)
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/operator delete operator new[]/operator delete[] 和 malloc/free用法一样。
他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。
实际operator new和operator delete只是malloc和free的一层封装。
new做了两件事
调用operator new分配空间。
调用构造函数初始化对象。
delete也做了两件事
调用析构函数清理对象
调用operator delete释放空间
new[N]
调用operator new分配空间。
调用N次构造函数分别初始化每个对象。
delete[]
调用N次析构函数清理对象。(思考这里怎么N是怎么来的?)
调用operator delete释放空间。
定位new表达式(replacement版本)
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
new (place_address) type
new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表。
class Array
{
public :
Array (size_t size = 10)
: _size(size )
, _a(0)
{
cout<<"Array(size_t size)" <<endl;
if (_size > 0)
{
_a = new int[ size];
}
}
~ Array()
{
cout<<"~Array()" <<endl;
if (_a )
{
delete[] _a ;
_a = 0;
_size = 0;
}
}
private :
int* _a ;
size_t _size ;
};
void Test ()
{
// 1.malloc/free + 定位操作符new()/显示调用析构函数,模拟 new和delete 的行为
Array* p1 = (Array*) malloc(sizeof (Array));
new(p1 ) Array(100);
p1->~Array ();
free(p1 );
// 1.malloc/free + 多次调用定位操作符new()/显示调用析构函数,模拟 new[]和delete[] 的行为
Array* p2 = (Array*) malloc(sizeof (Array)*10);
for(int i = 0; i < 10; ++i )
{
new(p2 +i) Array;
}
for(int i = 0; i < 10; ++i )
{
p2[i ].~Array();
}
free(p2 );
}
深度剖析new/delete & new[]/delete[]
class Array
{
public :
Array (size_t size = 10)
: _size(size )
, _a(0)
{
cout<<"Array(size_t size)" <<endl;
if (_size > 0)
{
_a = new int[ size];
}
}
~ Array()
{
cout<<"~Array()" <<endl;
if (_a )
{
delete[] _a ;
_a = 0;
_size = 0;
}
}
private :
int* _a ;
size_t _size ;
};
void Test ()
{
//
// 1.通过【调试】new/delete、 new[]/delete[]剖析系统在里面到底做了些什么?
// 2.分析delete[] 的对象是自定义类型时,是怎么知道要调用 N次析构函数的?
//
int* p1 = new int;
delete p1 ;
Array* p2 = new Array;
delete p2 ;
int* p3 = new int[10];
delete p3 ;
Array* p4 = new Array[10];
delete[] p4 ;
}