内存分区模型
根据c++执行将内存大致划分为4个区域:
- 代码区,存放函数体的二进制,即CPU执行的机器指令,并且是只读的;代码区中存放的就是CPU执行的机器指令,代码区是共享和只读的,共享是指对于频繁被执行的程序,只需要在内存中有一份代码就行。而只读则表示防止程序意外修改指令
- 全局区(静态区),存放全局变量和静态变量。全局区是全局变量、静态变量和常量区、字符串常量和const修饰的常量存放在这里。代码区全局区在代码编译后就存在了
- 栈区,由编译器自动分配释放,存放函数形参,局部变量,返回值等。不要返回局部变量的地址,栈区的数据由编译器开辟和释放。形参数据也是放在栈区的。栈区和堆区是程序运行后才有
- 堆区,由程序员分配和释放,若程序员不释放,程序结束时由操作系统CPU释放,堆区由程序员开辟,若程序员不释放,则由操作系统回收
内存溢出与内存泄漏
内存溢出:指程序在申请内存时,没有足够的内存空间供其使用
内存泄露 :指程序在申请内存后,无法释放已申请的内存空间
new & delete
- new创建类对象需要指针接收,new创建类对象使用完需delete销毁
- new创建对象直接使用堆空间(或全局区的静态存储区)而局部不用new定义类对象则使用栈空间
- new对象指针用途广泛,如作为函数返回值、函数参数等
- 频繁调用场合并不适合new,就像new申请和释放内存一样
new操作符是从自由存储区上为对象动态分配内存空间的,malloc函数是从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念, 凡是通过new操作符进行内存申请的, 该内存称为自由存储区。 而自由存储区的位置取决于operator new的实现细节。自由存储区不仅可以是堆, 也可以是静态存储区, 取决operator new在哪里为对象分配内存
使用new创建对象
CTest* pTest = new CTest();
delete pTest;
pTest是用来接收类的对象指针。new申请的对象,只有调用到delete时才会执行析构函数,如果程序退出而没有执行delete则会造成内存泄漏
不使用new,直接使用类定义声明
CTest mTest;
此种创建方式,使用完后不需要手动释放,该类析构函数会自动执行
#include <iostream>
using namespace std;
class A
{
private:
int n;
public:
A(int m):n(m)
{
}
~A(){}
};
int main()
{
A a(1); //栈中分配
A b = A(1); //栈中分配
A* c = new A(1); //堆中分配
delete c;
return 0;
}
第一个隐式调用,第二个显式调用,两者都是在进程虚拟地址空间中的栈中分配内存,而第三种使用了new,在堆中分配了内存,栈中内存的分配和释放是由系统管理,堆中内存的分配和释放必须由程序员手动释放
栈是机器系统提供的,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高
堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就需要申请足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
一般情况不使用new,直接使用类定义声明,申请内存特别大的情况下,或者作为函数返回值时,使用new创建对象。
new的作用是:
- 调用operator new分配空间。
- 调用构造函数初始化对象。
new[ ]的作用
- 调用operator new分配空间。
- 调用N次构造函数分别初始化每个对象。
具体调用是,new分配内存时,先调用malloc后调用构造函数,释放空间时,先调用析构函数,后调用free。
malloc & free
malloc/free是C/C++标准库的函数,malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员),通常情况下,C程序只能用malloc/free管理动态内存,malloc返回的是void*指针,单位是byte, 需要通过强转才能转成我们所需要的类型
(void *)malloc(int size)
char *p = (char *)malloc(100);
malloc函数申请的是连续的一块内存,内存分配会失败,函数返回NULL,分配空间之后需要用if(NULL!=p)进行验证,free函数只有一个参数,就是所要释放的内存块的首地址
free(p);
malloc需要与free配套使用,同时注意只能free一次,释放完块内存之后,没有把指针置NULL,这个指针就成为了“野指针”,因此free完之后,一定要给指针置NULL。
栈与堆
栈是系统管理的内存空间,存储局部变量,临时对象,函数参数等,大小有限
堆是程序员管理的内存空间,常用于创建对象,空间大,存储常用对象,适用于多次调用,跨线程场景,应该永远记住堆的内存管理是否合理,否则出现内存泄漏