C++内存管理

1. C/C++内存分布

 在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

  •   栈,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
  •   堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
  •   自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
  •   全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
  •   常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。

2.  C语言中动态内存管理方式:malloc/calloc/realloc/free

malloc:

 1.引用头文件stdlib.h
2.使用malloc()开辟内存空间
3.判断malloc()的返回值是否为空指针
4.使用malloc()开辟好的内存空间
5.使用free()释放malloc()开辟的内存空间
6.将指针置为NULL

动态内存分配内存图

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	//向内存申请40字节的空间,以整型的形式进行使用和管理
	int* ptr = (int*)malloc(40);
	//对malloc返回值进行判断
	if (NULL == ptr)
	{
		perror("malloc\n");
		return 1;
	}
	//使用开辟好的内存空间
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(ptr + i) = i;
	}
	//释放空间
	free(ptr);
	//将指针置为空指针
	ptr = NULL;
	return 0;
}

 有几个点需要注意:

1.使用malloc()后,要对返回值进行判断
2.使用结束后,要用free()对malloc()开辟的内存空间进行释放,最重要的是free()的参数是指向malloc()开辟内存空间的起始地址
3.内存空间释放后,将指针ptr置为空指针,否则会造成野指针问题。

calloc: 

1.calloc()函数向内存申请一块连续的空间,并将内存空间都初始化为0。
2.calloc()参数num表示分配num个元素的空间,size表示每个元素的大小,单位为字节。
3.calloc()函数的返回值为void*类型,如果内存空间开辟成功,则返回开辟的内存空间的起始地址;如果失败,则返回空指针(NULL)。
calloc()和malloc()的区别只在于calloc()会在返回地址之前把申请的空间的每个字节初始化为0。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	//向内存申请40字节的空间,以整型的形式进行使用和管理
	int* ptr = (int*)calloc(10 , sizeof(int));
	//对malloc返回值进行判断
	if (NULL == ptr)
	{
		perror("calloc\n");
		return 1;
	}
	//使用开辟好的内存空间
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(ptr + i) = i;
	}
	//释放空间
	free(ptr);
	//将指针置为空指针
	ptr = NULL;
	return 0;
}

calloc()的使用方法和malloc()的使用方法很相似,区别是calloc()的参数形式和malloc()的参数形式书写不同,另一个区别calloc()会在返回地址之前把申请的空间的每个字节初始化为0,而malloc()只开辟空间,不进行初始化。

realloc: 

1.realloc()函数的作用是对指针ptr指向的动态开辟的内存空间的大小进行调整。
2.realloc()的参数ptr,指向的是先前用malloc()、calloc()、realloc()开辟的内存空间的起始地址,或者,它可以是一个空指针,在这种情况下分配一个新的块(就像调用malloc一样)。
3.realloc()的参数size,表示调整后内存空间的大小。
4.realloc()的返回值是一个指向重新分配的内存空间的指针,它可以是与ptr相同的,也可以是一个新的位置。此指针的类型为void*,可以将其强制转换为所需的数据指针类型,以便可解引用。
5.如果函数分配请求的内存空间失败,则返回空指针,并且参数ptr所指向的内存块没有被释放(它仍然有效,且其内容不变)。

realloc()开辟空间存在两种情况 :

  • 情况一:原有空间之后有足够大的空间

 

  • 如果原有的内存空间之后有足够大的空间,要扩展内存就直接在原有内存之后追加内存空间,原来空间的数据不会发生变化
  •  情况二:原有的空间之后没有足够大的空间

 

如果是情况二的时候,原有空间之后没有没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间,将原来空间的数据拷贝到新开辟的内存空间中存放,并且将原来的内存空间释放。这样函数返回的是一个新的内存地址。 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	//向内存申请40字节的空间,以整型的形式进行使用和管理
	int* ptr = (int*)malloc(40);
	//对malloc返回值进行判断
	if (NULL == ptr)
	{
		perror("malloc\n");
		return 1;
	}
	//使用开辟好的内存空间
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(ptr + i) = i;

	}
	//对内存空间进行扩容
	int* p = (int*)realloc(ptr, 80);
	//当realloc开辟空间失败时,返回的是NULL
	if (p != NULL)
	{
		ptr = p;
		p = NULL;
	}
	//对新开辟的空间进行使用
	for (i = 10; i < 20; i++)
	{
		*(ptr + i) = i;
	}
	//释放空间
	free(ptr);
	//将指针置为空指针
	ptr = NULL;
	return 0;
}

 3. C++内存管理方式

C 语言内存管理方式在 C++ 中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因
C++ 又提出了自己的内存管理方式: 通过 new delete 操作符进行动态内存管理

new/delete操作内置类型

void Test()
{
  // 动态申请一个int类型的空间
  int* ptr4 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* ptr5 = new int(10);
  
  // 动态申请10个int类型的空间
  int* ptr6 = new int[3];
  delete ptr4;
  delete ptr5;
  delete[] ptr6;
}

注意:申请和释放单个元素的空间,使用 new delete 操作符,申请和释放连续的空间,使用
new[] delete[] ,注意:匹配起来使用。
在申请自定义类型的空间时, new 会调用构造函数, delete 会调用析构函数,而 malloc free 不会

4. operator newoperator delete函数

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

operator new和operator delete是系统提供的全局函数;

new在底层调用operator new全局函数来申请空间;
delete在底层通过operator delete全局函数来释放空间;

operator new实际上也是通过malloc来申请空间,如过malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常;
operator delete最终通过free来释放空间;

 

new和delete的实现原理

其中new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间;
new在申请空间失败后会抛异常,malloc会返回NULL;

自定义类型:
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来释放空间;

 

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值