动态内存管理分析

内存区域的划分

内存可以大块划分为系统占用不可访问的区域,剩下就是栈,堆,代码段,数据段(静态区)。
那么他们是如何分布在内存中的呢?
可以了解一下函数栈帧
内存分布
栈和堆都可以存放数据
注意:栈是从高地址到低地址生长的,而堆与它相反。

静态区是存放初始化和未初始化

代码段就是存放代码啦

C/C++中堆上的内存管理

在C/C++上内存管理分为两种:

1. 系统自动分配自动回收。

2. 手动分配手动释放

那么什么是系统自动分配自动释放的呢?
栈!在栈上分配的空间是系统自动分配自动回收,不用程序员自己管理,很是方便,但是有好就有坏,栈的空间比较小,在linux操作系统下默认是8M大小的栈,所以过度用栈很容易导致栈溢出。
手动管理的动态内存在堆上,那么可能会有疑问,堆有多大?可以说堆是非常大,这个其中存在这虚拟内存,详细自行百度。
(实际自己学术浅薄不能解释清楚^_^)

C++中在堆上开辟空间的关键字new及具体的实现

c++是C语言的加强版,也可以说是在C语言的基础上添加了需要多新的特性,比如,面向对象,当然也会添加一些关键字。new,delete就是其中的两个。
new关键字是用来开辟动态内存,也就是在堆上内存的分配。在C语言中我们也学过在堆上开辟空间的几个关键字,malloc ralloc calloc 都是在堆上开辟空间,而new关键字与他们不一样的是,它们只管开辟空间其他都没有,而new不一样,new添加了异常机制。更加的适用与面向对象的开发。
看new的具体实现机制。
new的具体实现其实还是借助了malloc的函数,在c++中new对malloc进行了封装,怎么封装,在new关键字里添加了operator new[] 这个函数,并且做了异常处理,在operator new[] 这个函数中还是用malloc实现的内存开辟。
new关键字的内部
这是在vs3013上对new的单步执行操作,就可以看到new里面是一个operator new[]函数的实现。而operator new[] 函数里面还可以进去可以看到用的是malloc来开辟空间,但是不能在vs2013上面进行测试,这个需要低一点版本才能看到,比如vs2008。

c++在堆上释放空间delete和delete[]

首先说明为什么会有delete和delete[]两个释放空间的。这个前面没有说到,其实是因为new在开辟空间时候可以一次开辟多个相同类型的对象。用的方式比如:

int *p = new int[3];

这样我就开辟出了3个int的空间。这样我们就有了一个问题delete可以释放一次new那么对于同类型的多个对象重复释放就尤为繁琐,而且在对象特别多的时候就很容易释放错误,所有就有了与之对应的delete[]。

关于new[]多个对象而用一个delete[]来释放的底层机制

new[] 在开辟空间的时候会多开出四个字节的空间,为什么要多开?因为需要保存开辟多个对象的个数,这样就可以很轻松的知道在初始化对象的时候需要调用几次构造函数。当空间用完时候,手动释放只需要一个delete[]系统就知道调用几次析构函数。这些就基于new[]时候多开辟的那四个字节。
具体细节我们用图示来看:
底层机制图
这样就很巧妙的解决了当开辟很多对象时候释放多或者少的问题了。

注意

在自定义类型中用new[]才会多开辟四个字节的空间,如果是内置类型就不会多开辟四个字节的大小

new、new[]与delete、delete[]的匹配问题

如果是这样那么是不是可以用new开辟出来的空间用delete[]来释放?
答案是不行的。首先要明确new和new[]虽然大体上都是开辟开辟空间,但是他们是有很多不同的,比如上面的图,是用new[]开辟出来的,就会自动的多开辟出四个字节,而new开辟空间就不会多开辟出四个字节的空间。(当然这里说的是自定义类型)。
那么用new开辟出来的空间能不能用delete[]释放呢?是绝对不行的。
原因是用new开辟出来的空间没有多开辟四个字节,而delete[]要多向前多释放四个字节的空间,但那本来就不是自己的空间,所以会出现访问内存出错,而导致程序奔溃。
如果用new[]开辟出来的空间能不能用delete释放呢?程序奔溃
因为释放位置错误。delete在释放时候没有向前移动四个字节。

那么如果用new开辟的用free释放可以吗?我们想一想,用new开辟的用free释放好像没有什么问题,但是仔细想想,new有异常机制,而且会调用构造函数,那么在程序结束需要调用析构函数,delete会而free不会调用,那么就有可能会造成内存泄漏。
如果用malloc开辟的空间那么用delete释放,想想会发生什么
有可能会奔溃,因为delete需要调用析构函数,如果析构函数中有内存的释放,那么就会奔溃。

如有不足,请多多指教~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值