C/C++内存分布:
内核空间是操作系统使用维护,用户不用对其进行管理。
栈又叫堆栈,非静态局部变量/函数参数/返回值等等
内存映射段,高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享内存,做进程间通信。
堆,用于程序运行时动态内存分配。
数据段,存储全局变量和静态数据。
代码段,可执行的代码/只读常量。
C语言动态内存管理方式:
从堆上进行动态内存分配:
申请内存:
malloc:
void* malloc (size_t size);
/*
用户所需内存空间大小的字节数;
不会对申请空间进行初始化。
*/
calloc :
void* calloc (size_t num, size_t size); // num-->申请元素个数
/*
会对申请成功的空间进行初始化--> 0;
*/
realloc:
void* realloc (void* ptr, size_t size); // ptr-->地址
/*
ptr == NULL 那么realloc等价于malloc;
ptr != NULL 对之前申请的空间进行调整,需要比较原空间和新空间大小。
如果缩小空间--> 返回原空间首地址;
扩大空间--> 扩大空间较少--> 返回原空间首地址
扩大空间较多--> 开辟newsize大小的新空间;
将旧空间元素拷贝到新空间;
释放旧空间;
返回新空间首地址。
*/
相同点: 都需要用户通过 free释放;
返回类型为 void*,所以要对返回结果进行强制类型转化;
申请失败返回NULL;
为防止用户使用越界,会对用户申请的空间会在前后各添加4字节的保护机制;
为维护用户申请的空间,每段申请的空间,都会花费36字节去管理。
int main()
{
int* p1 = (int *)malloc(sizeof(int)* 10);
free(p1);
return 0;
}
C++中动态内存管理方式:
空间的申请: new T /new T[ ]
int main()
{
// new后跟所申请空间的类型
int* p1 = new int; // 可以不对申请的单个元素空间初始化
int* p2 = new int(10); // 也可以初始化
int* p3 = new int[10] ; // 申请一段连续空间,但不能对其初始化
return 0;
}
new/new[]由于申请时已经给出其类型,所以之后不用进行类型转化;
空间的释放: delete add / delete[ ] add;
{
delete p1;
delete p2;
delete[] p3;
}
<必须匹配使用>
针对内置类型:
malloc/new/new[]
free/delete/delete[]
可以不匹配使用,因为调用内置类型不用对其进行构造。
自定义类型:
malloc:不调用构造函数初始化空间,它只会动态开辟和对象大小相同的一段空间。
free:只负责释放空间。
new:将对象空间开辟成功,再调用构造函数完成空间初始化。
delete:先调用析构函数释放对象中的资源,在释放对象所占的空间。
class Test
{
public:
Test(){
cout << "Test():" << _ptr << endl;
_ptr = new int;
}
~Test(){
cout << "~Test():" << _ptr << endl;
if (nullptr != _ptr){
delete _ptr;
_ptr = nullptr;
}
}
private:
int* _ptr;
};
int main()
{
Test* ptr1 = (Test*)malloc(sizeof(Test)); // 用malloc申请空间
delete ptr1; // 用delete来释放
}
因为malloc只能申请所需要的空间而不能构造对象,所以对象的成员变量为随机值,之后调用delete释放就使得程序崩溃。
类似的如果用new申请空间,free释放空间:
free只会释放对象的空间,但对象中的资源不会清理,这样就产生了内存泄漏。
如果用new[]申请一段空间,而用delete释放空间:
delete只释放一个单元空间,之后空间没办法释放程序崩溃。