内存管理【C++】

1.C++的内存分布

        【前情提要】我们在编写C++程序的时候,会构建多个函数,他们都会生成栈帧,创建的变量也需要空间进行存放,那我们如何才能知道,自己所创建的内容到底位于哪里呢?接下来我们来了解下C++程序中的内存划分。

        1. 又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。
        2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
        创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)
        3. 用于程序运行时动态内存分配,堆是可以上增长的。
        4. 数据段--存储全局数据和静态数据。(静态区)
        5. 代码段--可执行的代码/只读常量。(常量区)

int globalVar = 1;//全局变量,静态区
static int staticGlobalVar = 1;//静态变量,静态区
void Test()
{
    static int staticVar = 1;//静态变量,静态区
    int localVar = 1;//局部变量,栈区
    int num1[10] = { 1, 2, 3, 4 };//数组名代表整个数组,在栈区
    char char2[] = "abcd";
    //char2 和 *char2 两者是不同的,
    //char2 是数组名,在栈区
    //*char2 是对*char2的解引用,是首元素地址,a是首元素,a在栈上
    const char* pChar3 = "abcd";
    //pChar3是局部变量,在栈上
    //const修饰的是*pChar3,推出*pChar3 是首元素地址,是在常量区
    int* ptr1 = (int*)malloc(sizeof(int) * 4);//*ptr1动态开辟在堆区,ptr1是栈区
    int* ptr2 = (int*)calloc(4, sizeof(int));//同上
    int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
    free(ptr1);
    free(ptr3);
}

2.C语言中的内存管理方式:malloc/realloc/calloc/free

void Test ()
{
    // 1.malloc/calloc/realloc的区别是什么?
    int* p2 = (int*)calloc(4, sizeof (int));
    int* p3 = (int*)realloc(p2, sizeof(int)*10);
    // 这里需要free(p2)吗?
    //并不需要,free(p3)就会把p2也销毁了
    free(p3);
}

        这四者,大体的区别可以简单归为:直接开,初始开,重新开,倒闭。

3.C++的内存管理

3.1 new/delete操作内置类型

        C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

        还可以多次生成对象,对对象初始化,前几个初始化,其他则为默认值。

        注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。

3.2 new和delete操作自定义类型

class A
{
public:
    A(int a = 0)
    : _a(a)
    {
        cout << "A():" << this << endl;
    }
    ~A()
    {
        cout << "~A():" << this << endl;
    }
private:
    int _a;
};
int main()
{
    // new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间
    还会调用构造函数和析构函数
    A* p1 = (A*)malloc(sizeof(A));
    A* p2 = new A(1);
    free(p1);
    delete p2;
    // 内置类型是几乎是一样的
    int* p3 = (int*)malloc(sizeof(int)); // C
    int* p4 = new int;
    free(p3);
    delete p4;
    A* p5 = (A*)malloc(sizeof(A)*10);
    A* p6 = new A[10];
    free(p5);
    delete[] p6;
    return 0;
}

       new的对象,会去调用默认构造函数,而delete会去调用析构函数。new多少个对象则去调用多少次默认构造函数,delete[]则是调用多次析构函数。

        如果没有默认构造该怎么去new[]呢?

class A
{
public:
    A(int a1,int a2 = 1)
    {
        cout<<"A(int a1,int a2 = 1)"<<endl;
    }
    ~A()
    {
        cout<<"~A()"<<endl;
    }
private:
    int _a1;
    int _a1;
};
int main()
{
    //A* p1 = new A;没有默认构造就不支持这样初始化
    A* p2 = new A(2,2);
    A* p3 = new A(1);
    
    A* p4 = new A[2]{p2,p3};//严格来说这里就不是调用构造了
    //是调用拷贝构造了
    A* p5 = new A[2]{A(3,3),A(4,4)};//匿名对象也可以

    A* p6 = new A[2]{{5,5},{6,6}};//隐式类型转换可以
    return 0;
}

        注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

4. new和delete的实现原理

4.1 内置类型

        如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

4.2 自定义类型

        >new的原理:
                
1. 调用operator new函数申请空间//底层是malloc,相当于malloc plus
                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来释放空间

class A
{
private:
    int _a1;
};

int main()
{
    int* p1 = new int(1);
    free(p1)//这里会不会产生内存泄漏呢???
    //答:并不会,内置类型没有析构函数的概念,调用delete就是
    //调用operator delete,就是调用free,但是不推荐!!!


    A* p2 = new A;
    free(p2);//对于自定义类型呢,还能不能那样了
    //答:虽然程序不会崩,但是调用的时候并没有调析构
    //产生内存泄露了

    int* p3 = new int[10];
    delete p3;//这个也不会,new和delete都是malloc和free解决
    //没有构造和析构的概念

    return 0;
}

        有了以上的概念,我们看看一段有趣的代码,并解答下问题。

        

        我们将new A的代码屏蔽,只运行new B的,程序可以正常运行。

        但我们如果运行A的话,则程序崩溃了,这是什么原因呢????

        转到反汇编,我们可以看到,A的大小为84字节,但我们A类只有8字节,10个为80字节,那多出来的那部分,到底是哪里来的呢? 

 

  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值