C/C++内存管理

2023-09-15 18:54:33

1. C/C++内存分布

int globalvar = 1;
static int staticGlobalvar = 1;
void Test()
{
	static int staticVar = 1;
	int localvar = 1;

	int num[10] = { 1,2,3,4 };
	char char2[] = "abcd";
	const char* pChar3 = "abcd";
	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)malloc(4, sizeof(int));
	int* ptr3 = (int*)relloc(ptr2, sizeof(int) * 4);
	free(ptr1);
	free(ptr3);
}
  • 选项:A. 栈 B.堆 C.数据段(静态区) D.代码段(常量区)
  • globalvar:____ - staticGlobalar:_____ -staticVar:______
  • localVar:_____ - num1:____
  • char2:_____ - *char2:_____
  • pChar3:____ - *pChar3:____
  • ptr1:____ - *ptr1:_____
    C C C A A A A A D A B
  • sizeof(num1)=____ - sizeof(char2)=____ - strlen(char2)=______
  • sizeof(pChar3)=____ - strlen(pChar3)=____ - sizeof(ptr1)=______
    40; 5; 4(遇见\0截止); 4/8(是一个指针,和后面指向的东西没有关系,32位4,64位8); 4(有效字符的个数); 4/8(指针)
    在这里插入图片描述
  1. 又叫堆栈–非静态局部变量/函数参数/返回值等,栈是向下增长的
  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可以使用系统接口创建共享共享内存,做进程间通信
  3. :用于程序运行时的动态内存分配,堆可以是向上增长的。
  4. 数据段:存储全局数据静态数据
  5. 代码段:可执行的代码/只读常量

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

void Test()
{
	int* p1 = (int*)malloc(size(int));
	free(p1);

	//1.malloc/calloc/realloc的区别?
	int* p2 = (int*)calloc(4, sizeof(int));
	int* p3 = (int*)realloc(p2, sizeof(int) * 10);

	//这里需要free(p2)嘛?
	free(p3);
}

3.C++内存管理方式new/delete

不推荐malloc和free,C++的new/delete更简洁,对内置类型差别不大,自定义类型会调用构造函数和析构函数。

3.1 new/delete操作内置类型

int main()
{
	int* p1 = new int;//new不用检查,不会初始化。
	int* p2 = (int*)malloc(sizeof(int));//要去强转,VS2019检查严格
	if (p2 == nullptr)
	{
		perror("malloc fail");
	}
	return 0;
}
int* p3=new int(0);//初始化为0
delete p3;
int* p4=new int[10];//申请了10个int的数组
delete[] p4;
int* p5=new int[10]{1,2,3,4};//初始化

new可以帮助初始化

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一定要去匹配使用,不要交叉,否则结果不确定。

3.2 new/delete操作自定义类型

单个对象调单次构造函数,多个对象调多次构造函数。delete调析构函数
根本上而言,C和C++内存管理用一套模式

4. operator new和operator delete函数(重点)

4.1底层原理

库里面的全局函数operator new和operator delete,不是运算符重载。本质是malloc和free的封装。
new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是全局函数。new在底层调用delete new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间

int main()
{
	//出错机制不同
	//失败以后抛异常
	int* p1=(int*)operator new(sizeof(int*));
	//失败返回空nullptr
	int* p2 = (int*)malloc(sizeof(int*));
	if (p2 == nullptr)
	{
		perror("malloc fail");
	}

	//面向对象的语言处理错误时基本上使用抛异常。
	//new 1.申请空间 operator new,封装malloc 2.调用构造函数
	A* p3 = new A;//调用operator new
	
	//delete需先调用析构函数,在使用p3指向的空间
	delete p3;
	
    //申请空间 operator new[]->operator new->封装malloc
    //调用10次构造函数
	A* p6 = new A[10];
	delete[] p6;
    //delete需先调用10次析构函数,在使用operator delete[] p6指向的空间

    int* p7 = new int[10];
	free(p7);
	//不会造成内存泄露,因为针对的是内置类型,不会报错
	A* p8 = new A;
	free(p8);
	//不会报错。operator delete->free,只是没有调用析构函数,少调不会报错
	
	return 0;
}
class Stack
{
public:
	Stack()
	{
		cout << "Stack()" << endl;
		_a = new int[4];
		_top = 0;
		_capacity = 4;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
Stack st;
//调用构造,会调用析构

Stack* pst = new Stack;//指针,内置类型,不调用析构
//pst:4个字节,是个指针。new的机制:开空间,12个字节,开在堆上面,再调用构造函数,再去堆上开16个字节,也就是4个整型
delete pst;

在这里插入图片描述

  1. 先调用析构函数,完成栈指向的资源的清理
  2. 调用operator delete(pst),释放结构对象的空间。
  3. 由于底层的实现有关联交叉,不匹配使用可能有问题可能没有问题,因此最好要匹配使用
A* p9=new A[10];
free(p9);//报错
delete p9;//报错
delete[] p9;//没有问题

了解其底层机制

5.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在释放空间前会调用析构函数完成空间中资源的清理。
    用法+底层原理
int main()
{
	size_t size = 0;
	while (1)
	{
		int* p1 = (int*)malloc(1024 * 1024 * 4);

		if (p1 == nullptr)
		{
			break;
		}
		size += 1024 *1024* 4;
		cout << p1 << endl;
	
}
	cout << size << endl;
	cout << size/1024/1024 << "MB"<<endl;

}

C++出错抛异常。

在这里插入图片描述

int main()
{
	size_t size = 0;
	try
	{
		while (1)
		{
			int* p1 = new int[1024 * 1024];

				if (p1 == nullptr)
				{
					break;
				}
			size += 1024 * 1024 * 4;
			cout << p1 << endl;

		}
	}
	catch (const exception& e)
	{
		cout << e.what()<< endl;
	}
	
	cout << size << endl;
	cout << size/1024/1024 << "MB"<<endl;

}

在这里插入图片描述
bad allocation:申请内存失败。

6. 定位new表达式(placement-new)

定位new表达式是在一分配的原始内存空间中调用构造函数初始化一个对象
使用格式:
new(place_address)type或者new(place_address)type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表

int main()
{
	A aa;
	A* p1 = (A*)malloc(sizeof(A));
	if (p1 == nullptr)
	{
		perror("malloc fail");
	}//构造函数不能显式调用
	//对一块已有的空间初始化——定位new
	//new(p1)A;
	//定位new
	new(p1)A(1);//需要有参数
    //调用析构函数:
	p1->~A();
	free(p1);
	return 0;
}

//改进malloc
A* p2 = new A;
delete p2;

有一类场景需要这个malloc,需要提升性能,内存从内存池进行申请
在这里插入图片描述

更多推荐

Nacos身份绕过漏洞复现(QVD-2023-6271)

一、背景nacos安全预警,对问题复现后进行修复。漏洞原理为开源服务管理平台Nacos在默认配置下未对token.secret.key进行修改,导致远程攻击者可以绕过密钥认证进入后台造成系统受控等后果。漏洞信息漏洞类型:身份认证绕过漏洞等级:高危漏洞编号:NVDB-CNVDB-2023674205漏洞影响范围:0.1.

【QT--使用百度地图API显示地图并绘制路线】

QT--使用百度地图API显示地图并绘制路线前言准备工作申请百度地图密钥(AK)安装开发环境开发过程新建项目ui界面GPSManager类主窗口Map效果展示前言先吐槽一下下,本身qt学的就不咋滴,谁想到第一件事就是让写一个上位机工具,根据CAN总线传来的位置信息,在地图上去绘制路线,并获取当前路段的限速信息等。当听到

android系统编译

本文主要参考官方文档(http://source.android.com/download)和网上相关资料(http://blog.csdn.net/HKjinzhao/archive/2009/03/18/4002326.aspx,http://www.williamhua.com/2009/04/30/how-to

pg常用插件

pg软件包自带插件前言pg的插件是基于库的;pg的数据字典介绍:1、pg_stat_statements插件Pg_stat_statements是一个扩展,而不是核心数据库的一部分。它是一个contrib扩展,随postgres源代码一起提供。pg_stat_statements的功能位于一个名为pg_stat_sta

项目进度管理有哪些方法?项目管理中的进度管理

项目进度管理是项目实施过程中,根据制定的计划对各阶段的任务和项目最终完成的期限所进行的管理。在执行该计划的过程中,检查实际进度是否按计划要求进行,若出现偏差,便要及时找出原因,采取必要的措施或调整,直至项目完成。保证项目能在满足其时间约束条件的前提下实现总体目标。管事:项目进度管理主要涉及到对项目的任务进行分解,并设计

uniapp 使用subNVue原生子窗体显示弹框或悬浮框

效果展示在uniapp中,我们可以使用subNVue原生子窗体来解决web-view等原生页面中弹框无法显示的问题。subNVue原生子窗体是uniapp提供的一种原生组件,可以在uniapp中嵌入原生页面,并且可以与uniapp页面进行通信。我们可以在原生页面中使用uniapp提供的API来与uniapp页面进行通信

【开发篇】二、属性绑定与校验

文章目录1、@ConfigurationProperties自定义Bean属性绑定2、@EnableConfigurationProperties注解3、@ConfigurationProperties第三方Bean属性绑定4、松散绑定5、常用计量单位6、数据校验7、yaml绑定值的坑--关于进制1、@Configur

玩转 gpgpu sim 02记 —— 构建了什么

1.设置环境变量编译gpgpu-sim需要先运行脚本setup_environment,sourcesetup_environment,注释如下,主要是设置一些Makefile中会用到的环境变量#seeREADMEbeforerunningthis#下面这句用来检测当前的shell环境是不是bash或者sh或者zsh,

Jtti:新加坡云服务器怎么部署javaweb

在新加坡云服务器上部署JavaWeb应用程序需要执行以下步骤:1.准备云服务器:首先,您需要租用或创建一个新加坡地区的云服务器,确保服务器的操作系统和硬件资源满足您的需求。2.安装Java环境:确保您的服务器上已经安装了Java开发环境(JDK)。您可以使用以下命令来检查是否已经安装:java-version如果未安装

乖离率BIAS指标选股公式,判断多空力量和超买超卖

乖离率(BIAS)指标用于衡量股价与移动平均线之间的偏离程度,可以用来判断当前市场的多空力量和超买超卖情况。乖离率的计算公式比较简单,如下:BIAS=(收盘价-N日移动平均价)/N日移动平均价×100其中,N代表选择的时间周期,比如5日、10日或20日等。从公式可以看出乖离率BIAS的正负值表示股价相对于均线的偏离方向

思腾云计算

近日,IDC发布了《2022年H2中国加速计算市场分析报告》。报告显示,2022年加速服务器市场同比增长22.9%。中国加速服务器市场预计将在未来五年内保持稳定增长。IDC预测,到2027年,中国加速发展的服务器市场将达到163亿美元。思腾合力经过近几年的快速发展,已逐步成长为国内人工智能服务器领域领先企业。本次报告榜

热文推荐