【问题标题】:What happens to statically allocated memory after its scope ends?范围结束后静态分配的内存会发生什么?
【发布时间】:2013-09-07 02:53:59
【问题描述】:
void PrintArray()
{
  int a[4] = {4,3,1,5};
  for(int i=0; i<4; i++)
    cout<<a[i];
}

在这个函数的调用完成后,分配给指针变量“a”的内存和“a”指向的 4 整数块到底发生了什么? 块和指针变量的内存是否被解除分配,还是会造成某种内存泄漏?

【问题讨论】:

  • a 在这里不是指针,它是一个数组。数组衰减有时会指向指针。
  • 另外,a 不是一个静态变量。这是一个自动变量。
  • 简短回答。当函数返回时, a 会自动销毁。没有内存泄漏。如果您的代码中有newmalloc,请担心内存泄漏。

标签: c++ c memory-management dynamic-memory-allocation static-memory-allocation


【解决方案1】:

a 不是静态变量,它是 automatic 变量,来自 draft C99 standard 部分 6.2.4 对象的存储持续时间第 4 段 说:

一个对象,其标识符被声明为没有链接且没有存储类 说明符 static 具有自动存储持续时间。

第 3 段中,它将static 的生命周期描述为程序的生命周期,并且在第 5 段中说:

对于这样一个没有变长数组类型的对象,它的生命周期会延长 从进入与其关联的块直到该块的执行结束 反正。 [...]

换句话说,对于一个自动变量来说,它的生命周期会扩展到它的作用域,在这种情况下,as 作用域是函数PrintArray,并且在退出该作用域后,与它关联的存储就会被释放。

对于 C++,draft standard 中的相关部分是 3.7.3 自动存储持续时间第 1 段 说:

显式声明的块范围变量 register 或未显式声明的 static 或 extern 具有自动存储持续时间。这些实体的存储将持续到创建它们的块退出。

【讨论】:

    【解决方案2】:

    自动变量不是静态的,它们在其作用域的末尾(在函数的末尾)被处理掉。静态变量将持续存在,即使在函数中调用它也会保持其值。这里有一个关于extern/static variables 的链接以了解更多详情。

    【讨论】:

      【解决方案3】:

      内存没有泄漏。它不在堆上分配。现在,这里可能涉及 2 个不同的内存位置。

      1. { 4,3,1,5 } 初始值设定项的存储位置。通常,像这样的初始化程序存储在数据段中。在嵌入式系统中,这可能是只读闪存。在 PC 或其他任何设备上,这将只是一个 RAM 区域,它使用您的程序映像(例如 EXE)进行初始化并且不会被修改。函数退出后,它仍然存在。但这不是泄漏——只是程序内存占用的一部分(有些人可能会说是静态内存)。
      2. PrintArray() 函数范围内为a[] 分配的堆栈内存。编译器所做的是分配一些堆栈空间,然后从数据段复制函数开头的值。这通常会发生,因此如果您修改 a[] 中的任何元素,它只会影响该特定函数调用的数组。当PrintArray() 再次被调用时,原来的初始化器不会被修改并且可以重用。如果由于先前的调用改变了值而对PrintArray() 的后续调用初始化为{ 4,3,1,5 } 之外的其他内容,那将是奇怪的/出乎意料的。但是,您没有在此处修改它,因此优化可能不会在堆栈上分配任何东西是合理的。 YMMV。假设a[] 确实驻留在堆栈上,它将在函数退出时自动释放(因此auto 变量)。

      当然,确切地发生了什么取决于您的编译器、链接器、设置(尤其是优化)和目标。

      【讨论】:

      • 感谢您的精彩解释,但我主要感兴趣的是分配给 a 的 4-int 块。我真正想知道的是,如果该 4-int 块被某些人释放/释放其他用途还是只是在内存中保留直到程序结束。
      【解决方案4】:

      在 C 中,像 a 这样的自动对象在声明它的块的出口处被丢弃。

      【讨论】:

        【解决方案5】:

        指针变量'a'和'a'指向的4整数块

        首先,我们需要澄清一个基本的误解。 a 不是与 4 元素数组不同的单独指针变量; a 4 元素数组。 a 的地址和a[0] 的地址是一回事。在大多数情况下,表达式a从“int的四元素数组”类型转换为“指向int的指针”,而表达式是数组中第一个元素的地址。

        为了回答这个问题,由于a是在一个块中声明的,并且没有static关键字,它具有自动存储持续时间,这意味着当你释放数组占用的内存时离开封闭范围(在这种情况下,函数的主体)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-04-11
          • 2016-12-22
          • 1970-01-01
          • 2019-06-17
          • 2021-09-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多