『C++成长记』内存管理

慈云数据 2024-03-19 技术支持 47 0

🔥博客主页:小王又困了

📚系列专栏:C++

🌟人之为学,不日近则日退

❤️感谢大家点赞👍收藏⭐评论✍️

目录

一、C/C++内存分布

二、内存管理方式

📒2.1C语言内存管理方式 

📒2.2C++内存管理方式 

🎀2.2.1new/delete操作内置类型

🎀2.2.1new和delete操作自定义类型

三、operator new与operator delete函数

四、new和delete的实现原理

📒4.1内置类型

📒4.2自定义类型

五、定位new表达式(placement-new)

📒5.1概念

📒5.2使用格式

📒5.3使用场景

六、malloc/free和new/delete的区别

 七、内存泄漏

📒7.1什么是内存泄漏

📒7.2内存泄漏的危害

📒7.3内存泄漏分类

📒7.4检测内存泄漏

📒7.5避免内存泄漏


一、C/C++内存分布

    在C和C++中,内存分布主要包括以下几个部分:

代码段(Code Segment):

  • 包含程序的机器代码,也称为文本段。
  • 是只读的,存储程序的执行代码。
  • 在程序运行时不可修改。

    数据段(Data Segment):

    • 包括初始化的全局变量和静态变量。
    • 在程序开始运行时分配,并在整个程序的执行周期内保持不变。
    • 数据区(Data Section): 存储已经初始化的全局变量和静态变量。
    • BSS段(Block Started by Symbol): 存储未初始化的全局变量和静态变量。

      堆(Heap):

      • 程序员分配和释放的内存区域。
      • 动态分配的内存(例如使用new和malloc函数)存储在这里。
      • 堆的大小在程序运行时可以动态调整。

        栈(Stack):

        • 存储函数的局部变量和函数调用的上下文信息。
        • 由编译器自动分配和释放。
        • 栈的大小在程序运行时是固定的。

          堆栈区域之间的空间(Heap-Stack Gap):

          • 用于防止堆和栈之间的冲突。
          • 可以防止堆溢出覆盖栈数据或栈溢出覆盖堆数据。

             小Tips:这些区域在内存中的布局可能因操作系统和编译器而异,但通常遵循相似的结构。在运行时,栈的地址通常位于较高的内存地址,而堆的地址通常位于较低的内存地址。代码段和数据段的位置取决于可执行文件的加载方式,通常在较高的内存地址。 

            二、内存管理方式

            📒2.1C语言内存管理方式 

                C语言提供了一些基本的内存管理函数和操作符,使程序能够有效地分配和释放内存。以下是C语言中常用的内存管理方式:

            📝malloc() 和 free():

            • malloc()函数用于动态分配指定大小的内存空间。
            • free()函数用于释放先前由malloc()分配的内存空间。
            • 例子:
              // 分配10个整数大小的内存空间
              int *ptr = (int *)malloc(10 * sizeof(int));
              if (ptr != NULL) 
              {
                  // 使用内存
                  // ...
                  // 释放内存
                  free(ptr);
              }
              

              📝 calloc() 和 realloc():

              • calloc()函数用于分配指定数量和大小的内存空间,并将其初始化为零。
              • realloc()函数用于更改之前分配的内存块的大小。
              • 例子:
                // 分配并初始化为0,10个整数大小的内存空间
                int *ptr = (int *)calloc(10, sizeof(int));
                if (ptr != NULL)
                {
                    // 使用内存
                    // ...
                    // 重新分配内存空间为20个整数大小
                    ptr = (int *)realloc(ptr, 20 * sizeof(int));
                    // 使用重新分配后的内存
                    // ...
                    // 释放内存
                    free(ptr);
                }
                

                📝静态分配:

                • 静态分配是在编译时为变量分配内存空间。
                • 包括全局变量、静态变量和局部变量(在函数外部定义的变量是静态的)。
                • 内存分配和释放由编译器自动处理。

                  📝自动变量:

                  • 在函数内部定义的变量通常是自动变量。
                  • 自动变量的内存分配和释放由程序的执行控制流决定。

                    📝指针和动态内存分配

                    • 使用指针进行内存分配和释放是C语言中动态内存管理的重要部分。
                    • 必须小心管理分配的内存,以避免内存泄漏和悬空指针问题。

                       小Tips:C语言中的内存管理是相对低级的,程序员需要手动分配和释放内存。不正确的内存管理可能导致内存泄漏、悬空指针或者堆栈溢出等问题。因此,编写健壮和高效的代码需要仔细管理内存的分配和释放。

                      📒2.2C++内存管理方式 

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

                      🎀2.2.1new/delete操作内置类型

                      void Test()
                      {
                        // 动态申请一个int类型的空间
                        int* ptr1 = new int;
                        
                        // 动态申请一个int类型的空间并初始化为10
                        int* ptr2 = new int(10);
                        
                        // 动态申请10个int类型的空间,不初始化
                        int* ptr3 = new int[10];
                        // 动态申请10个int类型的空间,并初始化前三个
                        int* ptr4 = new int[10]{1,2,3};
                        delete ptr1;
                        delete ptr2;
                        delete[] ptr3;
                        delete[] ptr4;
                      }
                      

                      小Tips:用new开辟空间是不会进行初始化的。如果我们想动态申请并初始化,类型后面要跟圆括号 () ,动态申请多个连续空间,类型后面跟的是方括号 [ ] ,如果要对这多个连续的空间初始化,可以在 [ ] 的后面跟 { } , { } 里面是初始化的数据,初始化的值不够,后面会默认初始化为0。申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[ ]和delete[ ]。

                      🎀2.2.1new和delete操作自定义类型

                      class A
                      {
                      public:
                          A(int a = 0)
                              : _a(a)
                          {
                              cout 
微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon