前言:
C中的内存管理是通过new、new[]、delete、delete[]这4个关键字来实现的,之所以是关键字,是因为C需要在对象构造的时候自动去调用构造函数,对象析构的时候自动去调用析构函数,这些是编译器控制的,而原先C语言中的malloc()/free()本质上是库函数,是不受编译器控制的,所以编译器是无法将自动执行构造/析构函数的任务强加于malloc()/free()的。
一、内存分配方式:
C++中的内存分为5个区域,首先是栈、堆,栈中主要存储的是局部变量,用完即销,处理器分配内存(指令集),可分配的内存较小(毕竟是处理器里面);堆中则是通过new/delete手动申请的内存,大小受限于当前计算机的有效虚拟内存大小。接下来则是3个区域,分别是全局数据区(包含静态数据)、常量区(字符串)以及代码段(二进制代码)。
对于栈和堆,可以再说细一些,栈是由机器系统来决定的,所以栈顶地址和栈的容量都是一开始(程序启动的时候)就决定好的,而且栈中的地址都是通过寄存器来分配存放的,所以效率高(压栈和弹栈都是指令进行的),所以效率是较高的,栈本身也有静态分配和动态分配,动态分配是通过alloca()函数,这两个分配都是编译器来决定的,栈的地址是从高到低,而且是连续的内存,因为栈本身的结构是先进后出,并不会有哪一块内存还在中间就被弹出来;那么对于堆,使用堆是会有内存碎片的隐患,因为堆是人为手动申请的(效率较低),所以堆内存是不连续的,系统管理堆是通过链表来连接每一块堆内存,当堆内存不够用的时候,系统会去申请新的内存来扩展数据段的内存空间,然后堆就有机会分到足够大小的内存(这部分不清楚,数据段和堆不是分开的么?有空问问)。
堆中的数据都是需要通过指针来访问的,然而栈上的数据是可以直接访问的。
二、new/delete的实现机制
-
malloc()
和free()
都是内存管理函数。但是new和delete都是C++中的关键字。因为C++在对象创建和销毁的时候,都要自动执行构造函数和析构函数。但是malloc()和free()都是库函数,是不在编译器的控制范围内的,是不能将构造函数和析构函数的任务强加在malloc()/free()上的。
-
在C++中new和delete是关键字,也是一种运算符,这些运算符的底层也是通过调用库函数
malloc()/free()
来实现的。 -
new在整个调用过程中完成的工作主要是:
(1). 调用operator new()来分配指定大小的未被初始化的空间
(2). 调用构造函数对类对象进行初始化
(3). 返回新分配并构造好的对象指针new本身并不会直接开辟内存
-
delete在整个调用过程中完成的工作主要是:
(1). 调用对象的析构函数,对打开的文件进行关闭
(2). 释放指针指向空间的内存free和delete只是会释放指针指向空间的内存,对指针本身没有任何处理,所以为了防止野指针,在释放内存后,要及时将指针置为null
-
new和delete的运算符重载:
因为new关键字会先进行
分配内存
,然后再对内存进行对象初始化
。但是频繁地对堆内存
进行申请和释放会造成内存碎片,内存不足等情况,所以可以通过内存池的方法,从而每次创建对象的时候,不用新开辟内存,而是直接调用构造函数进行对象初始化即可。