C 和 C++ 内存管理

目录:
一:C和C++内存分布
二:C动态内存管理方式
三:C++动态内存管理方式
四:operator newoperator delete函数
五:newdelete的实现原理
六:定位new表达式(placement-new)
七:经典面试题

WeChat_20240806081718

思维导图:

1:C 和C++ 内存分布

 栈区:向着低地址的方向增长

堆区:向着高地址的方向增长;不支持静态内存的开辟。

接下来我们来做个题:

 以下变量存放在哪一个区域:

 1.1变量区域存放

问题1:

 globalVar在哪里?_静态区___       staticGlobalVar在哪里?静态区____


 staticVar在哪里?_静态区___       localVar在哪里?_栈区___


 num1 在哪里?_栈区___

 char2在哪里?_栈区___              *char2在哪里?_栈区__
 pChar3在哪里?_栈区___        *pChar3在哪里?__常量区__
 ptr1在哪里?__栈区__             *ptr1在哪里?_堆区___

 

想必对于*pchar3 和 *char2 的 的存放区域应该有不少友友们错了吧。

对于这2个变量首先需要知道对应代码所表示的含义

char char2 [] = "abcd" ;
表示: 使用一个常量字符串来初始化字符数组char2 ,*char2 就是数组的第一个元素,存放在栈区的
const char* pChar3 = "abcd" ;
表示: 使用一个常量字符串来初始化一个pChar3 这个指针 ,注意此时指针存放的是首字符的地
址,这个常量字符串是存放在常量区 的
注意:局部静态变量也是存放在静态区的

 

问题2:

 sizeof ( num1 ) = ____ ;  
  sizeof ( char2 ) = ____ ;       strlen ( char2 ) = ____ ;
  sizeof ( pChar3 ) = ____ ;     strlen ( pChar3 ) = ____ ;
  sizeof ( ptr1 ) = ____ ;
1.2 区域分布

1.)又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的(低地址)
 

2. )内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
 

创建共享共享内存,做进程间通信。
 

3. )用于程序运行时动态内存分配堆是向上增长的(高地址),是不支持静态分布的。
 

4.) 数据段(也被称为数据区、静态数据区、静态区)--存储全局数据和静态数据
 

5.) 代码段(常量区)--可执行的代码/只读常量 

2:C动态内存管理方式
void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);

int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);

free(p3 );
}
2.1 malloc,realloc,calloc 区别

malloc:在堆上开辟一块空间,不进行初始化

realloc:进行对空间的扩容,可能原地扩,也可能异地扩

calloc:开辟空间并把开好 的空间进行初始化

注意:当realloc ,calloc 函数的第一个参数为空的时候,此时调用函数的功能和malloc功能

一样

2.2 动态开辟的内存需要frre? 

毋庸置疑的,必须进行释放,否则会造成内存泄漏

3:C++动态内存管理方式 

   通过 new 和 delete 操作符 进行动态内存管理。

 康康以下的问题:

这是因为:对于st2这个栈没有进行初始化,就尾插数据,所以会导致出现随机值。 

 忘记初始化对于程序员来说,是常有的事情。针对动态申请的空间有没有一种机制:既可以动态

的开空间又同时进行初始化呢

new 和 delete 这2个操作符就是针对此问题产生的。

new:申请动态空间的同时进行构造函数的调用来完成对空间的初始化。


3.1 对内置类型的处理

     //注意:申请和释放单个元素的空间,使用new和delete操作符后面加变量名字


    // 申请和释放连续的空间使用new[ ]和delete [ ]


    //注意:匹配起来使用

3.2对自定义类型的处理

 对于自定义类型的delete 和内置类型的销毁是不一样的在底层逻辑上:

当st 这个对象出了作用域的时候,st 这个对象占用的空间就会归还系统,但是此时_a所指向

的堆上动态申请的数组是无法进行释放的,所以就造成内存泄露问题

delete pst 的机制:会去先调用析构函数完成堆上空间的释放;之后出了作用域pst这个变量

销毁。

注意:

申请自定义类型对象的空间时,new会调用构造函数,delete会调用析构函数,而malloc与

free不会。

 3.3双重 new 和 delete

 对于自定义类似的数据释放以及开空间其实是双重new 和delete

3.4 new 和 delete  一定要匹配使用 

 

4:operator newoperator delete函数

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

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

new在底层调用operator new全局函数来申请空间

delete在底层通过operator delete全局函数来释放空间。

operator new 实际对malloc函数的一个封装,如果malloc申请空间成功就直接返回,否

则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常

operator delete其实的对free的封装。

5:newdelete的实现原理

new , delete 对自定义类型的处理机制

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 来释
放空间
6:定位new表达式(placement-new)

定位 new 表达式是在 已分配的原始内存空间中调用构造函数初始化一个对象
使用格式:
new (place_address) type 或者 new (place_address) type(initializer-list)
place_address 必须是一个指针, initializer-list 是类型的初始化列表
使用场景:
定位 new 表达式在实际中一般是 配合内存池使用 。因为内存池分配出的内存没有初始化,所
以如 果是自定义类型的对象,需要使用new 的定义表达式进行显示调构造函数进行初始化。

 使用:

7:经典面试题
7.1malloc,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 在释放空间
前会调用析构函数完成 空间中资源的清理
7.2  new 的意义

1)简化了用法

2)解决了自定义类型的初始化问题 

7.2内存泄漏定义以及危害
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序 未能释放已经不再使用的内存 的情
况。内 存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错
误,失去了对 该段内存的控制,因而造成了内存的浪费
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,
出现 内存泄漏会导致 响应越来越慢,最终卡死。
  • 61
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 40
    评论
评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值