1054 字
5 分钟
【C++】空间管理
2024-08-20

在程序运行中,电脑的内存空间是有限的,因此我们要对内存进行管理,使得程序运行时不会因为内存不足而崩溃,尤其是避免内存泄漏的问题。

内存存储区域#

C++中,内存存储区域主要有以下几种:

  • 静态存储区域
    静态存储区域用来存储全局变量和静态变量(如静态局部变量和静态成员变量)等。这些内存空间在程序编译完成时就已经分配好,并在程序结束时被销毁,变量的生命周期存在于程序运行期间。
  • 栈空间
    栈空间用来存储局部变量(不包括static修饰的局部变量)、函数参数等。这些变量在函数调用结束后会被销毁,生命周期只存在于函数调用期间。栈空间的管理由编译器自动完成。
  • 堆空间
    堆是用来动态分配内存的区域,程序员可以通过newmalloc等函数来请求分配内存,并通过deletefree来释放内存。堆内存的生命周期由程序控制。
注意

栈空间和堆空间之间有些区别:

  • 栈空间是编译器自动管理的,而堆空间是程序员手动管理的。栈空间在函数调用结束后会自动销毁,而堆空间需要程序员手动释放
  • 栈空间的大小通常是固定的,而堆空间的大小受限于内存限制
void Demo() {
    int *p = nullptr; // 申请一个栈空间 p
    p = new int[5]; // 申请一个堆空间 int [5]
    delete[] p; // 释放堆空间 int[5]
} // 销毁栈空间 p

栈空间#

在C++中,代码块是一种特殊的语句块,用于定义一个代码块,代码块中的语句会按照顺序执行。代码块由花括号 { } 包含,并且可以嵌套在其他代码块中。代码块可以包含任何类型的语句,包括变量声明、函数调用、条件语句、循环语句等。
代码块里面的变量声明和函数调用,会在代码块结束后被销毁,生命周期只存在于代码块中。

代码块里产生的变量存在于栈空间里,会随着代码块的结束而销毁。

void Demo() {
    int a = 1;
    {
        int b = 2;
    } // b 会被销毁
} // a 会被销毁

堆空间#

使用malloc#

我们可以使用cstdlibmallocfree函数来申请和释放堆空间,单位为字节。

#include <cstdlib>

void Demo() {
  void *buffer = std::malloc(64); // 申请64字节的堆空间
  if (buffer != nullptr) { // 判断堆空间是否申请成功
    // TODO 使用 buffer
    std::free(buffer); // 使用完要进行释放
  } else {
    // TODO 异常操作
  }
}

使用opreator new#

operator new是一个特殊的操作符,用于在堆上分配内存,区别于new,它只分配内存,不进行初始化,单位为字节。
需要注意的是,使用operator new时,如果分配失败,operator new会抛出一个异常,而不是返回一个空指针,这里我们需要使用try catch自行捕获异常,并进行处理。

void Demo() {
    void *buffer = nullptr; // 定义一个空指针
    try {
        buffer = ::operator new(16); // 申请16字节的堆空间
    } catch (const std::exception &errmsg) { // 捕获异常
        // TODO 错误处理
    }
    // TODO 使用 buffer
    auto array = static_cast<uint8_t *>(buffer); // 把内存转换为数组,类型为uint8_t
    for (int i = 0; i < 16; i++) array[i] = i;
    ::operator delete(buffer); // 释放堆空间
}

使用new#

对于具体类型的变量,我们可以使用new来申请堆空间。
new实际上是调用了operator new,再对申请到的空间进行初始化。

void Demo() {
  int *pIntArray = new int[10];
  // TODO 使用 pIntArray
  delete[] pIntArray;
  pIntArray = nullptr;
}

注意事项#

注意
  • 栈区的变量在函数调用结束后会被销毁,有自己的生命周期,而堆区的变量需要我们手动释放,否则会造成内存泄漏;
  • 堆区没有类型定义,如何使用内存空间取决于空间的使用方。