内存管理(C/C++)

C/C++内存分布

先介绍C/C++中程序内存区域的分划

在这里插入图片描述

观察下列代码,分析各数据在内存中所处的位置

int i = 1;
static int statici = 1;
void test()
{
	static int staticn = 1;
	int n = 1;
	
	int arr[10] = { 0 };
	char ch[] = "crush";
	const char* p = "crush";

	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);
}
A.栈   B.堆   C.数据段(静态区)   D.代码段(常量区)
i在哪里__                    statici在哪里__
staticn在哪里__              n在哪里__
arr[]在哪里__

ch[]在哪里__                 *ch在哪里__
p在哪里__                    *p在哪里__
ptr1在哪里__                 *ptr1在哪里__

sizeof(arr)=__
sizeof(ch)=__               strlen(ch)=__
sizeof(p)=__                strlen(p)=__
sizeof(ptr1)=__              

在这里插入图片描述

在这里插入图片描述

栈:存储非静态局部变量,函数参数,返回值等
堆:程序运行时进行内存分配
数据段:存储全局数据和静态数据
代码段:可执行程序,只读常量

C语言中的动态内存管理方式

malloc/calloc/realloc 和 free
代码如下

void test()
{
	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(ptr2)  这里需要free(ptr2)吗?
	free(ptr3);
}

由于已经在ptr2的基础上进行了扩容,所以不需要对ptr2进行释放,否则就会发生错误

在这里插入图片描述

C++中动态内存管理

new / delete 操作内置类型

void test()
{
	int* p1 = new int;                   //C++动态申请一个int类型的空间
	int* p2 = (int*)malloc(sizeof(int)); //C动态申请一个int类型的空间
	delete p1;
	free(p2);

	int* p3 = new int[10];                    //C++动态申请10个int类型的空间
	int* p4 = (int*)malloc(sizeof(int) * 10); //C动态申请10个int类型的空间
	delete p3;
	free(p4);

	int* p5 = new int(1);                //C++动态申请一个int类型的空间并初始化
	int* p6 = new int[5]{ 1,2,3,4,5 };   //C++动态申请5个int类型的空间并初始化
	delete p5;
	delete[] p6;
}

new/delete 和 malloc/free 针对内置类型没有任何区别

void test()
{
	//动态申请一个int类型的空间
	int* p1 = new int;
	//动态申请一个int类型的空间并进行初始化
	int* p2 = new int(1);
	//动态申请5个int类型的空间
	int* p3 = new int[5];
	delete p1;
	delete p2;
	delete[] p3;
}

在这里插入图片描述

C++动态申请和释放空间时,需要配对,若是单个元素,使用new/delete;若是多个元素使用new[]/delete[]

new 和 delete 操作自定义类型

class M
{
public:
	M()
		:_data(1)
	{
		cout << "M()" << endl;
	}
	~M()
	{
		cout << "~M()" << endl;
	}
private:
	int _data;
};

void test()
{
	//C++动态申请一个M类型的空间
	M* p1 = new M;
	//C动态申请一个M类型的空间
	M* p2 = (M*)malloc(sizeof(M));
	delete p1;
	free(p2);

	//C++动态申请5个M类型的空间
	M* p3 = new M[5];
	//C动态申请5个M类型的空间
	M* p4 = (M*)malloc(sizeof(M) * 5);
	delete[] p3;
	delete p4;
}

int main()
{
	M m;
	test();
	return 0;
}

在这里插入图片描述

在申请自定义类型的空间时,new会调用构造函数,delete也会调用析构函数;相反malloc 和 free 则不会

operator new 和 operator delete 函数

operator new 和 operator delete 函数

new / delete C++是进行动态内存申请和释放的操作符, operator newoperator delete是系统提供的全局函数,换一种说法便是,new 申请空间是通过调用 operator new来实现的,同理 delete 释放空间也是通过调用operator delete来实现的

本质上,operator new/operator delete的用法与 malloc/free 的功能完全一样,不同点在于,处理动态申请失败的方式不同;malloc申请失败返回NULL,operator new申请失败则会抛异常

以下三种动态申请空间和释放的效果是一样的

void test()
{
	int* p1 = new int;
	delete p1;

	int* p2 = (int*)operator new(sizeof(int));
	operator delete(p2);

	int* p3 = (int*)malloc(sizeof(int));
	free(p3);
}

在这里插入图片描述

new 和 delete 的实现原理

内置类型

申请的是内置类型的空间,new/delete 与 malloc/free 的区别在上面已经结束过,这里便不在赘叙

自定义类型

new的原理

  1. 调用operator new函数申请空间
  2. 在已经申请的空间上调用构造函数,完成对象的实例化

delete的原理

  1. 在已经申请的空间上调用析构函数,完成对象中资源的清理
  2. 调用operator delete函数释放对象的空间

new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
  2. 在已经申请的空间上调用N次构造函数

delete[]的原理

  1. 在释放的对象空间上调用N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

定位 new 表达式(placement-new)

定位new表达式是在已经分配的原始内存空间中调用构造函数初始化一个对象

使用格式
new(place-address)type或者
new(place-address)type(initalizer-list)

使用场景
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定位表达式进行显示调用构造函数并进行初始化

class M
{
public:
	M(int m = 0)
		:_m(1)
	{
		cout << "M()" << endl;
	}
	~M()
	{
		cout << "~M()" << endl;
	}
private:
	int _m;
};

void test()
{
	//p现在指向的是与M对象大小相同的一段空间
	//还未调用构造函数,所以指向的不算是对象
	M* p = (M*)operator new(sizeof(M));
	//定位new,显示调用构造函数并进行初始化已经申请的空间
	new(p)M;//new(p)M(1);
	//显示调用析构函数
	p->~M();
	operator delete(p);
}

常见面试题

malloc / free 和 new / delete 的区别

malloc/free 和 new/delete的共同点:都是从堆上申请空间,并且使用完之后需要进行释放

  1. malloc 和 free是函数,new和delete是操作符
  2. malloc申请的空间不进行初始化,new可以进行初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需要在其后跟上空间的类型即可,如果多个对象,[]中指定对象个数即可
  4. malloc的返回值是void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  6. 申请自定义类型对象时,malloc/free 只会开辟空间,不会调用构造函数和析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

内存泄漏

什么是内存泄漏,内存泄漏的危害

内存泄漏的概念:内存泄漏是指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费

内存泄漏的危害:长期运行的程序出现泄漏,影响很大。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值