内存管理
- c/c++中内存分布
- sizeof 与 strlen
- c 语言中动态内存管理方式
- malloc
- calloc
- realloc
- c++ 中动态内存管理
- new 与 delete
- 自定义类型空间的动态分配
- new 与 delete 的实现
- operator new 与 operator delete
- 基本概念辨识
- malloc/free 与 new/delete 区别 *****
- 内存泄漏
c/c++中内存分布
c/c++ 中程序内存的区域划分:
分析下列代码中变量的存储地址:
int glob = 1;
static int staglob = 1;
int main()
{
static int a = 1;
int b = 2;
int num1[10] = { 1,2,3,4 };
char str1[] = "abcd";
const char* pchar = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4,sizeof(int));
int* ptr3 = (int*)realloc(ptr2,sizeof(int) * 4);
free(ptr1);
free(ptr3);
return 0;
}
存储结构分析:
sizeof 与 strlen
sizeof:计算类型大小
strlen:计算字符长度,遇到 \0 结束
但是考虑一个问题:
为什么在 malloc 、calloc、realloc 了三个变量空间之后,只进行释放(free)了两次?
这就是我们接下来要讨论的一个问题。
c 语言中动态内存管理方式
malloc
void malloc( size_t size );
动态申请空间,但不进行初始化操作
由于返回值为 void 类型,因此在使用时需要进行类型强转
空间使用结束需要手动 free,否则会造成内存泄漏
malloc 申请到的空间内容为随机值:
calloc
void calloc( size_t num, size_t size );
动态申请空间,并将申请到的空间初始化为 0
由于返回值为 void 类型,因此在使用时需要进行类型强转
空间使用结束需要手动 free,否则会造成内存泄漏
calloc 申请到的空间内容会初始化为 0:
realloc
void *realloc( void *memblock, size_t size );
在原有的空间基础上进行空间的重新申请,并会释放回收原有的空间,不会进行初始化操作
空间使用结束需要手动 free,否则会造成内存泄漏
realloc 重新开辟新空间并会释放掉旧空间,不会进行初始化:
realloc 重新分配空间之后,会自动释放掉原有空间,因此只需要空间释放一次,并且在重新分配空间时会保持相应位置空间内容不变(扩容:原有大小内容不变,后序新空间为随机值;缩小容量:空间内容与原内容保持一致)
c++ 中动态内存管理
因为 C++ 兼容 C语言,因此在 C++ 语言当中,依旧可以使用 malloc 、calloc、 realloc 来进行动态内存管理,并且在使用结束之后手动 free 释放空间,避免造成内存泄漏。
new 与 delete
C++ 中也常通过 new 和 delete 来进行动态内存的管理:
new T:申请单个 T 类型的空间
new T[N]:申请N个T类型的一段连续空间
new T(a):动态申请一个 T 类型空间,并初始化为 a
new T[n]{…}:动态申请 n 个 T 类型的连续空间,并在 {} 中进行初始化操作
delete 变量名 :释放单个空间
delete[] 变量名:释放连续空间
在使用 new 与 delete 进行动态内存管理时候要注意对应:
申请单个空间 new T —> 释放单个空间 delete;
申请连续空间 new T[] ---->释放连续空间 delete[];
int main()
{
int* p1 = new int; //申请单个 int 空间
int* p2 = new int[10]; //申请 10 个 连续的 int 类型空间
//初始化
int* p3 = new int(10);
int* p4 = new int[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
//空间的释放
delete p1;
delete[] p2; //释放空间应与创建空间匹配----连续的空间
delete p3;
delete[] p4; //释放空间应与创建空间匹配----连续的空间
return 0;
}
由此可见,C++中动态内存管理 new / delete 不需要进行类型的强转
自定义类型空间的动态分配
(1)使用传统的 C 语言 malloc / free 进行动态内存的管理:
class Test {
public:
Test() :_data(1)
{
cout << "Test()" << this << endl;
}
~Test()
{
cout << "~Test()" << this << endl;
}
private:
int _data;
};
int main()
{
Test* p1 = (Test*)malloc(sizeof(Test)); //单个 Test 类型空间
free(p1);
Test* p2 = (Test*)malloc(sizeof(Test) * 10); //连续 10 个 Test 类型空间
free(p2);
return 0;
}
(2)使用 C++ 中 new / delete 进行动态内存管理:
class Test {
public:
Test() :_data(1)
{
cout << "Test()" << this << endl;
}
~Test()
{
cout << "~Test()" << this << endl;
}
private:
int _data;
};
int main()
{
Test* p1 = new Test; //申请单个 Test 空间
delete p1; //释放单个空间
Test* p2 = new Test[10]; //申请连续10个 Test 空间
delete[] p2; //释放连续空间
return 0;
}
对于自定义类型的动态内存管理,倘若没有进行匹配释放空间则会造成程序崩溃或内存泄漏:
new 与 delete 的实现
在申请自定义类型的空间时,new 会调用相应的构造函数对空间进行初始化操作,delete 会调用相应的析构函数进行资源的清理:
operator new 与 operator delete
new 与 delete 是 C++ 中用户进行动态内存申请和释放的操作符;
operator new 与 operator delete 是系统提供的全局函数,new 在底层调用 operator new 全局函数来申请空间,delete 在底层通过 operator delete 全局函数来进行释放。
(一)operator new
new 申请空间,要么申请成功,要么报错,因此不需要进行判空。
new 申请新空间(自定义类型):
(1)内置类型直接调用 operator new 申请空间;
(2)自定义类型空间,先在堆上进行申请空间,其次调构造函数对空间进行初始化操作。
该函数实际上是通过 malloc 来申请空间(operator new 实际上是对 malloc 的封装),当 malloc 申请空间成功直接返回;申请失败,会进行相应不足应对措施:
检测是否是空间不足------若提供空间不足应对措施,则执行并继续 malloc;若没有提供则会发出 bad_alloc 类型异常。
通过反汇编来查看底层调用:
(二)operator delete
该函数实际上是通过 free 进行释放空间的。
delete 释放空间:
(1)若是内置类型,直接将空间释放;
(2)若是自定义类型空间,先调用析构函数进行资源的清理,其次将空间清理掉。
通过反汇编来查看底层调用:
内置类型创建连续空间,则会多次调用构造函数对空间进行初始化;
内置类型释放连续空间,则会多次调用析构函数对空间资源进行清理;
operator new 与 operator delete 支持重载,但一般情况下不用。
基本概念辨识
malloc/free 与 new/delete 区别 *****
相同点:
两者都是从堆上进行空间的申请,并且需要手动进行释放;
不同点:
(1)malloc/free 是函数(需要头文件),new/delete 是操作符(不需要头文件);
(2)malloc 申请的空间不会进行初始化(内容为随机值),new 可以进行初始化;
(3)malloc 申请空间时,需要手动计算空间大小并进行传参,new 只需要在其后跟上空间类型即可;
(4)malloc 返回值为 void* ,因此在使用时候需要进行类型强转,new 不需要;
(5)malloc 申请空间失败时返回 NULL,因此需要判空,new不需要—直接报错;
(6)申请自定义类型对象时,malloc/free 指挥开辟空间,不会调用构造函数与析构函数,而 new 在申请空间后会调用自定义类型对象的构造函数进行对象初始化,delete 在释放空间前会调用析构函数完成对象空间中的资源清理工作。
内存泄漏
内存泄漏:
指的是因为疏忽/错误造成程序未能释放已经不能使用的内存的情况。
内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的操作,因而造成了内存的浪费。
内存泄漏的危害:
长期运行的程序出现内存泄漏,影响很大,例如 操作系统、后台服务等,出现内存泄漏会导致相应越来越慢,最终卡死。
内存泄漏分类:
(1)堆内存泄漏
指程序执行中依据需要分配通过 malloc、calloc、realloc、new 等从堆上分配的一块内存,用完后必须通过相应的 free、delete 进行删除。
假设程序设计错误导致这部分内存没有被释放,那么以后这部分空间将无法在被使用,会产生 Heap Leak.
(2)系统资源泄漏
指程序使用系统分配的资源,例如 套接字、文件描述符、管道等没有使用相应的函数释放掉,导致系统资源的浪费,严重可导致效能减少、系统执行不稳定。
欢迎评论留言哈~~~