【C/C++内存管理】

本文详细解释了C/C++中内存分布,包括栈、堆、数据段和代码段的区别,以及C/C++中动态内存管理的malloc、realloc、calloc和C++的new/delete操作。重点介绍了operatornew和operatordelete的作用,以及如何定位new和避免内存泄漏及其危害。
摘要由CSDN通过智能技术生成


前言

(本文为个人学习时的笔记和部分个人思想,如有理解误区或者知识点的缺少还请麻烦指出哦)


一、C/C++内存分布

1.C语言内存分布

我们要先来看下面的代码和问题:

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "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);
}


看以上代码来思考回答以下问题:

选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)

globalVar在哪里?__C__ staticGlobalVar在哪里?__C__

staticVar在哪里?__C__ localVar在哪里?__A__

num1 在哪里?__A__

char2在哪里?__A__ *char2在哪里?_A__

pChar3在哪里?__A__ *pChar3在哪里?__D__

ptr1在哪里?_A___ *ptr1在哪里?__B__
  1. globalVarstaticGlobalVarstaticVar都是存再内存空间中的静态区中。(作用域不一样但是他们的生命周期都是一样的)

  2. localVarnumchar2因为都是函数内的变量所以都是存储在内存空间中栈的部分。

  3. char 2是存在栈空间里,char 2这段代码会在栈空间开辟五个字节存放’a,b,c,d,\0’,而char 2是数组名,数组名是这个空间的首元素地址。所以cahr 2是第一个元素的地址。在栈空间。

  4. Pchar3也是一样都是变量名都存放在栈空间,*Pchar3存放在代码段(常量区)。注意这里Pchar3和char2是不一样的,char2 [ ]是在栈空间开辟的空间,而 const char pChar3是用存在常量区的“abcd”在给它赋值。且Pcahr3的字符串数组是不能被修改的。

  5. ptr1是指针变量名,变量名都是放在栈空间上。不过ptr1指向的空间是malloc出来的。ptr 1是它开辟出来的空间,所以ptr 1指向的是堆空间

我们看下图来具体体会他们在内存中存放的位置。
在这里插入图片描述
内存分区:

  1. 存放非静态变量/函数参数/返回值等,地址由下增长。
  2. 内存映射段(共享区),用于装载一个共享的动态内存库,让用户可以使用系统接口创建共享内存。用于进程之间通讯。(等我滴Linux博客补到这里再细说)
  3. – 用于程序运行时动态内存分配,堆是可以上增长的。(比如malloc等创建出来的空间出来的空间)
  4. 数据段–存储全局数据静态数据
  5. 代码段 – 存放我们可以执行的代码和只读常量。

二、C/C++中动态内存管理方式

1.C语言内存管理malloc/realloc/calloc的区别

在这里插入图片描述
他们的区别
malloc是在堆中开辟了一块空间,calloc在malloc的基础上把内部空间初始化为0。
realloc是在一块空间的基础上扩容,也可以直接开辟一块空间,需要注意的是如果realloc时如果物理上它后面的内存放不下需要扩容的空间,realloc就会再选择一块空间扩容。
需不需要free(pc)
这里不用free(pc),这里如果realloc正常扩容的话pc和pr指向的是同一块空间,如果realloc异地扩容的话它原本指向的空间就会被释放掉(pc会自动被free掉)。

2.C++内存管理

2.1new/delete操作内置类型

在C++中更新了新的内存管理操作符:new和delete
new和delete在操作内置类型时和malloc/free都是有着同样的功能。
不过更为简洁方便。
注意:new/delete和malloc/free最好不要交叉混用

在这里插入图片描述

这里初始化多个空间时想要同时初始化在“ [ ] ”后加上“ { } ”作为初始化值。
在这里插入图片描述

2.2 new/delete操作自定义类型

new/delete和malloc/free的最大区别就是在自定义类型这里前者会自动调用构造函数和析构函数。后者需要手动初始化和清理空间。
在这里插入图片描述
在这里插入图片描述

2.3 new A[ ] 和 delete[ ] A(了解)

我们来看以下代码:
在这里插入图片描述
这里无论使用free和delete都会造成报错。
只能使用delete [ ] 才不会报错。

为什么呢?(注意这里每个编译器实现机制不同)
在这里插入图片描述
在这里插入图片描述
所以还是最好要匹配使用

int main()
{

	A* p1 = new A[10];

	//free(p1);
	//delete p1;
	delete[] p1;
	return 0;

}

2.4malloc/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在释放空间前会调用析构函数完成空间中资源的清理

三、 operator new与operator delete函数(重点理解)

new和delete用户进行动态内存申请和释放的操作符operator new 和operator delete系统提供的全局函数new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

  1. operator new 底层是调用malloc实现的,如果当malloc内存申请失败时,operator new会抛异常。
    在这里插入图片描述

  2. operator delete会检测是否出现越界,最终还是相当于调用free

四、定位new

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

place_address是一个开辟好的内存空间指针(还没有调用构造函数初始化),initializer-list是类型的初始化列表

int main()
{
// p1现在指向的只不过是与A对象相同大小的一段空间,
//还不能算是一个对象,因为构造函数没有执行
	A* p1 = (A*)malloc(sizeof(A));
	new(p1)A; // 注意:如果A类的构造函数有参数时,此处需要传参
	p1->~A();
	free(p1);
	
	A* p2 = (A*)operator new(sizeof(A));
	new(p2)A(10);
	p2->~A();
	operator delete(p2);
return 0;
}

五、内存泄漏

1.什么是内存泄漏,内存泄漏的危害。

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值