C/C++内存管理

  • Post author:
  • Post category:其他




C/C++内存管理



C++

兼容

C语言



C++

的内存管理机制和

C语言

是一样的,但是

C语言



malloc

函数已经无法满足

C++

面对对象过程中销毁的需求,于是

C++

提出了新的内存管理函数

new



delete



1. C/C++内存分布


将内存分成不同的区域是为了更好的管理,上面说过C++兼容C,所以内存分布都是一样的:



五大分区:


  1. 栈区:



    又叫

    堆栈

    ,用于存储非静态局部变量、函数参数、返回值等等,



    是向下增长的

  2. 内存映射段:

    内存映射段

    是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信

  3. 堆区:



    用于程序运行时动态内存分配,堆是可以上增长的

  4. 数据段:

    数据段

    用于存储全局数据和静态数据

  5. 代码段:

    代码段

    用于存储可执行的代码和只读常量


内存中还存在

内核空间

,但普通用户代码无法读写



2. C++动态内存管理


内存管理是为了对内存进行分类,使操作系统对内存能有更让的管理,

C++

提出了

new



delete

操作符进行动态内存管理,下面我们来讲讲使用细节



2.1 new和delete操作内置类型


代码演示:

void Test()
{
	int* ptr1 = new int; //申请一个整型,只是开空间
	delete ptr1; //释放

	double* ptr2 = new double(6.66); //申请一个浮点型,并初始化为6.66
	delete ptr2; //释放

	int* ptr3 = new int[8]; //申请8个int类型的空间
	delete[] ptr3; //释放8次
}



2.2 new和delete操作自定义类型


代码演示:

class A
{
	A(int a = 12)
		:_a(a)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};

int main()
{
	//new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数
	A* p1 = (A*)malloc(sizeof(A)); //开空间
	A* p2 = new A(12); //开空间并初始化
	free(p1);
	delete p2;

	//内置类型是几乎是一样的
	int* p3 = (int*)malloc(sizeof(int));
	int* p4 = new int;
	free(p3);
	delete p4;

	A* p5 = (A*)malloc(sizeof(A) * 10); //开10个A类对象空间
	A* p6 = new A[10]; //开10个A类对象空间
	free(p5);
	delete[] p6;

	return 0;
}



总结:



  1. new

    不需要像

    malloc

    那样进行空指针判断,也不需要进行类型转换


  2. delete

    需要配套使用,比如

    new int

    使用

    delete



    new int

    使用

    delete[]



  3. new



    delete

    都可以用于自定义类型,会分别调用自定义类型的

    构造函数



    析构函数



  4. new/delete



    malloc/free

    最大区别是

    new/delete

    对于

    【自定义类型】

    除了开空间还会调用

    构造函数



    析构函数



  5. malloc

    对应

    free



    new

    对应

    delete

    ,一定要搭配使用,避免引发问题



3. operator new 和 operator delete函数



new



delete

是用户进行动态内存申请和释放的操作符,

operator new



operator delete

是系统提供的全局函数,

new

在底层调用

operator new

全局函数来申请空间,

delete

在底层通过

operator delete

全局函数来释放空间


Visual studio 2019中operator new底层实现:

void* __CRTDECL operator new(size_t const size)
{
	for (;;)
	{
		if (void* const block = malloc(size))
		{
			return block;
		}

		if (_callnewh(size) == 0)
		{
			if (size == SIZE_MAX)
			{
				__scrt_throw_std_bad_array_new_length();
			}
			else
			{
				__scrt_throw_std_bad_alloc(); //抛出异常
			}
		}
		// The new handler was successful; try to allocate again...
	}
}


Visual studio 2019中operator delete底层实现:

void __CRTDECL operator delete(void* const block, size_t const) noexcept
{
	operator delete(block);
}

void __CRTDECL operator delete(void* const block) noexcept
{
#ifdef _DEBUG
	_free_dbg(block, _UNKNOWN_BLOCK);
#else
	free(block);
#endif
}


Visual studio 2019中operator new[]底层实现:

void* __CRTDECL operator new[](size_t const size)
{
	return operator new(size); //原理调用的size次operator new函数
}


Visual studio 2019中operator delete底层实现:

void __CRTDECL operator delete[](void* const block) noexcept
{
	operator delete(block);
}
void __CRTDECL operator delete[](void* const block, size_t const) noexcept
{
	operator delete[](block);
}



4. new 和 delete实现原理



4.1 内置类型


如果申请的是内置类型的空间,

new



malloc



delete



free

基本类似,不同的地方是:

new/delete

申请和释放的是单个元素的空间,

new[]



delete[]

申请的是连续空间,而且

new

在申请空间失败时会抛异常,

malloc

会返回

NULL



4.2 自定义类型


new的原理:

  1. 调用

    operator new

    函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造


delete的原理:

  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2. 调用

    operator delete

    函数释放对象的空间


new T[N]的原理:

  1. 调用

    operator new[]

    函数,在

    operator new[]

    中实际调用

    operator new

    函数完成N个对

象空间的申请

  1. 在申请空间上执行N次构造函数


delete[]的原理:

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用

    operator delete[]

    释放空间,实际在

    operator delete[]

    中调用

    operator delete

    来释放空间



5. 定位new



定位new



new

的新用法,是为了对已经开辟但没有初始化的空间进行初始化



5.1 基本语法



定位new

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


使用格式:

new(指针)type

或者

new(指针)type(初始化列表)

代码使用:

class A
{
public:
	A(int a)
		:_a(a)
	{
		cout << "A()" << endl;
	}
	~A() {
		cout << "~A()" << endl;
	}

private:
	int _a;
};
int main()
{
	A* p = (A*)malloc(sizeof(A));
	if (p == nullptr) {
		perror("malloc is failed");
		exit(-1);
	}
	new(p)A(1); //定位new,对已经定义的对象初始化

	return 0;
}



5.2 使用场景


使用场景:一般配合内存池使。因为内存池分配出的内存没有初始化,所以如果定义自定义类型对象,需要使用

new

的定义表达式进行显示调用构造函数进行初始化



C/C++内存管理到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!


文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正



版权声明:本文为cw412524原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。