计算机内存管理
计算机存储区域
在计算机中,存储区域主要分为:
- 硬盘
- 内存
- 高级缓存
- 寄存器
他们的运行速率自下而上加快,与之相应的造价越高。其中,硬盘的运行效率最慢,寄存器的效率最快。
C++内存分区
在C++ 中,内存主要分为五个区,分别是:
- 代码区
- 全局(静态)数据区
- 栈区
- 堆区
代码区
代码区是用来储存程序的所有代码,以及字符串常量等在编译期间就能确定的值,在程序的整个生命周期内, 在常量数据区的数据都是可用的。在这个区域内,所有的数据都是只读的,不可以修改本区域的数据,之所以这样,是因为在实际的实现中,最底层内部存储格式的实现会使用特定的优化方案。比如说,编译器可能只把字符串常量存储一次,而在几个重叠的对象里面引用它。
全局(静态)数据区
是用来存储全局静态变量的存储区域。只有在程序启动的时候才被分配,直到程序开始执行时才被初始化,比如:函数的静态变量就是在程序执行到定义该变量的代码时才被初始化的。在静态区数据区中没有被初始化的区域可以通过void*
指针来访问或操纵,但是static
定义的静态变量只能在本文件中使用,不可在其它文件中声明使用。
栈区
栈区主要存放编译器在需要的时候自动分配,在不需要的时候自动销毁的变量。主要是局部变量和函数的参数等,在函数调用和传参的时候,编译器为局部变量或形参开辟空间,注意,在这块空间中,编译器并不会自动对它进行任何的初始化,它所保存的不是0,而是一个随机值(可能是该储存区上次被使用后的值),在函数结束后,所开辟的空间将自动销毁,里面所存的内容将不复存在,也就是释放存储区的内容。 这就是为什么老师们在讲课中,最喜欢用的字眼:参数压栈和弹出。
堆区
堆区是一个动态的存储区域,使用库函数malloc()
和free()
,和操作符new
和delete
以及一些相关变量来进行分配和回收,在堆区中,对象的生命周期可以比它存在内存中的生命周期短,换句话说:程序可以获得一片内存区域而不用马上对它进行初始化,同时,在对象被销毁后,也不用马上收回它所占用的内存区,在这段时间内,用户可以还可以用void*
型的指针访问这片区域,但是原始对象的非静态区以及成员函数都不能被访问或者操纵,因为我们知道实际上对象已经不存在了。
全局(静态)数据、堆、栈空间的生命周期
new、delete实现机制
new[]、delete []实现机制
malloc、free和new、delete的区别
-
malloc
开辟空间类型大小需手动计算,new
是由编译器自己计算。 -
malloc
返回类型为void*
,必须强制类型转换对应类型指针,new
则直接返回对应类型指针。 -
malloc
开辟内存时返回内存地址要检查判空,因为若它可能开辟失败会返回NULL
,new
则不用判断,因为内存分配失败时,它会抛出异常bac_alloc
,可以使用异常机制。 - 无论释放几个空间大小,
free
只传递指针,多个对象时delete
需加[]
。 -
malloc
、free
只是开辟空间并释放,new
、delete
则不仅会开辟空间,还调用构造函数和析构函数进行初始化和清理。 -
new
、delete
底层是基于malloc
、free
来实现的,而malloc
、free
不能基于new
、delete
实现。 - 因为
new
、delete
是操作符,它调用operator new
、operator delete
,它们可以被重载,在标准库里它有8个重载版本,而malloc
、free
不可以重载。 - 对于
malloc
分配内存后,若在使用过程中内存分配不够或太多,这时可以使用realloc
函数对其进行扩充或缩小,但是new
分配好的内存不能这样被直观简单的改变。 - 对于
new
、delete
若内存分配失败,用户可以指定处理函数或重新制定分配器new_handler(可以在此处进行扩展),malloc
、free
用户是不可以处理的。 -
malloc
是在堆上分配内存的,但new
其实不能说是在堆上,C++中,对new
申请内存位置有一个抽象概念,它为自由存储区,它可以在堆上,也可以在静态存储区上分配,这主要取决于operator new
实现细节,取决与它在哪里为对象分配空间。