3

我正在阅读这篇文章并看到:“本文假设您已经了解并至少基本了解了 GNU/Linux 系统中的内存映射是如何工作的,特别是在堆栈中静态分配的内存和在堆栈中动态分配的内存之间的区别堆。”

这让我很困惑,因为我认为堆栈和堆是动态分配的,这意味着仅在必要时才分配,而全局变量和在函数内部声明为“静态”的变量是静态分配的,即始终分配。

例如,如果我有

void f() {
    int x = 1;
    ...
}

值 1 仅被放入堆栈,堆栈指针仅在函数 f() 被调用时才递增。同样,如果我有

void f() {
    int x = malloc(1 * sizeof(int));
    ...
}

只有调用 f() 时才会分配该堆内存。但是,如果我有“int x = 1;” 在程序的全局部分或“static int x = 1;” 在函数体内,每当我运行这个程序时,该内存将在数据部分中分配,值为 1。

我错了吗?

4

3 回答 3

4

静态变量只初始化一次,即使初始化语句在函数体内也是如此。

检查维基百科示例:

#include <stdio.h>

void func() {
    static int x = 0; 
    /* x is initialized only once across five calls of func() and
      the variable will get incremented five 
      times after these calls. The final value of x will be 5. */
    x++;
    printf("%d\n", x); // outputs the value of x
}

int main() { //int argc, char *argv[] inside the main is optional in the particular program
    func(); // prints 1
    func(); // prints 2
    func(); // prints 3
    func(); // prints 4
    func(); // prints 5
        return 0;
}

堆栈基本上是一个大型静态分配的数组,带有一个从它的开头开始的可移动指针。当您调用一个函数(从 main 开始)时,指针移动(创建一个堆栈帧)并且堆栈帧中的空间被切分并提供给局部变量(您有多少局部变量决定了函数的堆栈帧有多大将会)。所以局部变量是动态的(它们只有在你进入函数后才会出现),但堆栈是静态大小的。如果你在它上面分配了一个超大的结构或者使用了太多的递归,你会越过终点,操作系统会让你失望——这种现象被称为stackoverflow。( 这堆栈溢出图标图标实际上说明了这一点。底部的灰色容器代表堆栈所在的静态数组。橙色矩形是由函数调用创建的框架。就像在适当的堆栈溢出中一样,帧会溢出容器并繁荣——你的程序已经死了。帧上升的事实说明了堆栈的另一个相当特殊的事情 - 新帧的地址比旧帧低,因此堆栈溢出确实发生在堆栈数组的开头而不是它的结尾(除非您将数组视为从它们的最大索引开始,到 0 结束)。)

于 2015-10-10T17:40:34.243 回答
3

堆栈本身是静态分配的。随着控制流进入和离开它们的范围,堆栈中分配的变量来来去去。

于 2015-10-10T17:37:35.517 回答
2

堆栈以堆栈帧为单位分配。

  • 当一个函数被调用时,会为其分配一个栈帧,
  • 当一个函数返回时,它的栈帧消失,

而且,堆栈有助于存储函数参数和局部变量。

在函数获得其堆栈帧后,是的,在堆栈帧内,函数根据需要动态使用它的字节。


像堆一样动态分配堆栈

如果你想像堆一样在堆栈上分配内存,那么你可以使用alloca()from <alloca.h>,它比堆更快,但在大多数情况下你不需要它,它有缺点,因此在一般情况下不建议使用。


在不同的上下文中描述堆栈分配可能会更清楚:

  • 从 linux 的角度来看thread,(顺便说一下,每个进程默认创建 1 个线程,作为主线程),堆栈大小固定并在线程创建时分配,(2Mb 用于 IA-32,32Mb 用于 IA- 64,默认),您可以根据需要更改默认大小。所以你可以说这是固定的,静态的。
  • function内部线程或进程的角度来看,堆栈帧是在函数启动时从线程的堆栈内存中为其分配的,而堆栈帧会在函数结束时消失。
  • 从函数内部的非静态的角度来看local variable,变量是根据需要从函数的堆栈帧中动态分配的。

所以,它应该被称为静态还是动态,你来决定。

于 2015-10-10T17:39:24.200 回答