• C++内存分布介绍


    今天更新一下C++内存分布和管理的东西,这玩意就是考验你的基础扎不扎实

    1.C++内存分布

    直接上图

     上图右边这段最好是牢记

    内核空间就不说了,咱不管

    栈区:那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。函数调用建立栈帧,参数、函数中局部变量都存在栈帧中,栈是向下增长的,向下增长的意思是:从栈申请的内存地址会越来越小,在栈区当中是先使用高地址再使用低地址。

    内存映射段也不管

    堆区:一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。理论上而言,后malloc的内存地址比先malloc的要大,但是也不一定,但是不一定,因为有可能下一次申请的是之前其他空间释放回来的,这个区一般都很大,在32位系统下,可以占差不多3G的样子

    数据段:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的(DATA段)和未初始化的(BSS段),在C++里面没有这个区分了,它们共同占用同一块内存区

    代码段:可执行代码其实就是二进制指令,这里是存放二进制代码的。通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。 在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

    看完了右边再来看左边,左边的代码如下:

    下列变量分别存储在哪

    1. int globalVar = 1;//全局变量
    2. static int staticGlobalVar = 1;//静态数据
    3. void Test()
    4. {
    5. static int staticVar = 1;//静态数据
    6. int localVar = 1;//栈帧里面
    7. int num1[10] = {1, 2, 3, 4};//
    8. char char2[] = "abcd";
    9. char* pChar3 = "abcd";
    10. int* ptr1 = (int*)malloc(sizeof (int)*4);
    11. int* ptr2 = (int*)calloc(4, sizeof(int));
    12. int* ptr3 = (int*)realloc(ptr2, sizeof(int)*4);
    13. free (ptr1);
    14. free (ptr3);
    15. }

    globalVar是全局变量所以它在数据段

    staticGlobalVar是静态变量所以它在数据段

    staticVar是静态变量所以它在数据段

    localVar创建在test函数栈帧中,它是局部变量,在栈区

    num1是数组,在函数栈帧中创建,存储在栈区

    char2是数组,在函数栈帧中创建,存储在栈区

    *char2拿到的是字符a的地址,因为char2是数组,里面的元素也是存储在栈帧里面的,所以*char2也在栈区

    pchar3是指针变量,存储在栈区,它指向字符串的首字符地址

    *pchar3是常量字符a,常量字符串是存储在常量区的,就是在代码段

    ptr1是指针变量,他存储在栈区

    ptr1指向的内存空间是malloc出来的,所以*ptr1是在堆区

    2.C++内存管理

    这里要回忆一下C语言中动态内存管理的知识:malloc  realloc和calloc分别是什么?

    calloc等价于malloc+memest(0),开空间+初始化为0

    realloc是对malloc或calloc的空间进行扩容

    接下来就引入C++中的内存管理,就是new和delete

    注意:malloc和free是库函数,而new和delete只是操作符

    1. void Test()
    2. {
    3. //C语言 malloc等是库函数
    4. int* p1 = (int*)malloc(sizeof(int));
    5. free(p1);
    6. //C++ new/delete是操作符
    7. // 动态申请一个int类型的空间
    8. int* ptr4 = new int;
    9. // 动态申请一个int类型的空间并初始化为10
    10. int* ptr5 = new int(10);
    11. delete ptr4;
    12. delete ptr5;
    13. }

    那么两者的区别是什么?

    如果动态申请的对象是内置类型,用malloc和new没有区别,如果动态申请的对象是自定义类型,有区别,因为new和delete不仅仅会开空间/释放空间,还会调用构造函数和析构函数

    这里注意一点在new数组的时候,delete一定要加[],否则可能出错

    接下来还有一点要知道的是operator new和operator delete函数

    new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间

    我们在new一个对象T时,其实编译器会这样做:

    1、申请内存,调用operator new(底层其实是将malloc的封装实现)

    2、调用构造函数

    在delete时,编译器会这么做:

    1、调用T的析构函数

    2、调用operator delete(底层其实是将free的封装实现)

    说完了调用,那么如果调用失败呢?

    如果是malloc,就会返回NULL;

    如果是new,就会抛一个异常出来

    对于上述提到的自定义类型,new和delete的原理是什么呢?

    new的原理
    调用operator new函数申请空间
    在申请的空间上执行构造函数,完成对象的构造
    delete的原理
    在空间上执行析构函数,完成对象中资源的清理工作
    调用operator delete函数释放对象的空间
    new T[N]的原理
    调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申

    在申请的空间上执行N次构造函数
    delete[]的原理
    在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
    调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

    内存泄漏

    最后一点 malloc和new的使用就必然设计到内存泄漏的问题

    内存泄漏:在堆上申请了的空间,在我们不用了以后也没有释放,就存在内存泄漏,因为你不用了,也没有还给系统,别人也用不了

  • 相关阅读:
    微服务的发展历程的详细说明及每个阶段主流的架构和组件
    用例图 UML从入门到放弃系列之三
    【前端面试】- 输入URL到页面加载的全过程(一)
    自定义类型:结构体
    Python语言:算术运算符知识点讲解
    35分钟了解sql注入-盲注(三)
    顺序表详解——遍历、增添、查找、删除、修改、清除
    【CCF】第30次csp认证——202305-1重复局面
    【HTML专栏4】常用标签(标题、段落、换行、文本格式化、注释及特殊字符)
    Android 顶部标签栏及内容列表的设计与实现
  • 原文地址:https://blog.csdn.net/yzy521wjm/article/details/126680978