C++中的全局内存管理是在堆栈还是堆中?

78
如果我在 C++ 应用程序中全局声明一个数据结构,它会消耗堆栈内存还是堆内存?
例如:
struct AAA
{

.../.../.
../../..
}arr[59652323];

2
另外,全局变量和静态变量(在函数内部)之间有什么区别?它们必须存在于程序的整个生命周期中... - user128026
同意,但是可访问性有所不同。 - sameer karjatkar
@dspinozzi:全局变量的构造函数在main()函数之前调用,但静态变量的构造函数在第一次调用函数时调用。这两种类型的变量通常存储在相同的内存部分中--我认为GCC将它们放在.data节中。 - Neil
9个回答

143

由于我不满意答案,并希望sameer karjatkar想要学习的不仅仅是简单的是/否答案,所以在这里给出更多解释。

通常一个进程有5个不同区域的分配内存

  1. 代码 - 文本段
  2. 已初始化数据 - 数据段
  3. 未初始化数据 - BSS段

如果你真想了解每个区域保存了什么,请阅读并收藏以下链接:

编译器、汇编器、链接器和装载程序:简介(查看表格w.5)

程序在内存中的解剖

alt text


这是否意味着未初始化数据 - bss 和已初始化数据是堆的一部分? - sameer karjatkar
不,它们不是堆的一部分,正如我在答案中所写的那样,它们位于不同的区域(5个不同的区域)。堆和栈占据文本和数据段上方的虚拟内存。 - Milan
8
重要的是程序在首次加载到内存时分配 bss 和 data 段,它们的大小在运行时不会改变。相比之下,堆的内容是易失性的,在执行过程中随着动态内存操作而改变。 - quark
3
让栈向下增长,堆向上增长的想法是为了让它们可以以任意比例使用可用内存,但是加载动态库是否会阻止这一点呢? - danijar
将指针初始化为NULL是放在数据段还是bss段中? route_t* tblhead = NULL; - philx_x

34
这里的问题是问题本身。假设你有一个类似这样的小的C(C++也一样,它们处理方式相同)程序:
/* my.c */

char * str = "Your dog has fleas.";  /* 1 */
char * buf0 ;                         /* 2 */

int main(){
    char * str2 = "Don't make fun of my dog." ;  /* 3 */
    static char * str3 = str;         /* 4 */
    char * buf1 ;                     /* 5 */
    buf0 = malloc(BUFSIZ);            /* 6 */
    buf1 = malloc(BUFSIZ);            /* 7 */

    return 0;
}
  1. 这个变量既不是在栈上分配,也不是在堆上分配。相反,它作为静态数据分配,并且在大多数现代机器上被放入自己的内存段中。实际的字符串也被分配为静态数据,放在只读段中,这是一个良好的编程习惯。
  2. 仅仅是一个静态分配的指针;在静态数据中只有一个地址空间。
  3. 指针是在栈上分配的,因此当main函数返回时,它将被有效地释放。由于其为常量,字符串被分配在静态数据空间中。
  4. 实际上与第2种情况完全一样。关键字static告诉您不要在栈上分配它。
  5. ...但buf1在栈上,
  6. ...malloc的缓冲区空间位于堆上。
  7. 顺便说一下,孩子们不要在家里尝试这个。 malloc的返回值很重要;你应该始终检查返回值。

例如:

char * bfr;
if((bfr = malloc(SIZE)) == NULL){
   /* malloc failed OMG */
   exit(-1);
}

1
动态分配的缓冲区空间与全局变量无关,只有指针是全局的。请不要让人们更加困惑。 - EFraim
10
不要傻了,提问者显然对哪里应该放什么不够清楚,所以我写了一个回答来帮助他更好地理解。 - Charlie Martin

14
通常情况下它既不消耗堆内存也不消耗栈内存,而是尝试将它们分配到一个内存段中,在程序执行期间该内存段的大小可能保持不变。这个内存段可以是bss、stack、heap或data。

通过编辑boot.ini文件,我们可以将虚拟内存扩展到3GB。同样,是否有关于内存段的设置? - sameer karjatkar
这是没有意义的,因为静态分配内存的大小永远不会改变。 - Philippe Leybaert

6

全局内存在固定的内存块或堆上预先分配,具体取决于应用程序的分配方式:

byte x[10]; // pre-allocated by the compiler in some fixed memory block
byte *y

main()
{
   y = malloc(10); // allocated on the heap
}

编辑

这个问题有些混乱:如果我在C++应用程序中全局分配一个数据结构,它会消耗堆栈内存还是堆内存?

"分配"可以有很多种方式,包括调用malloc()。如果问题是“如果我声明并初始化一个全局数据结构”,那么情况就不同了。

很多年前,当CPU还在使用64K段的时候,一些编译器聪明地从堆中动态分配内存,而不是在.data段中保留一个块(因为内存架构的限制)。

我想我只是太老了……


它说“在堆上分配”,这是相当正确的。除非这个问题被标记为“初学者”或“新手”,否则这应该足以提醒正在发生的事情。 - Don Johe
@Don:不是的。全局变量是指针,不是它指向的内存。你可以按照自己的方式处理内存。也不是永远存在于整个运行过程中。有时甚至可以将其指向堆栈。 - EFraim
1
如果有一个教训可以从中吸取的话,那就是你应该避免回答问题,如果问题的确切含义不清楚。我的答案并不是错的,只是有些人认为他们对一个词的解释足以反对任何不支持他们观点的东西。即使现在,问题提出10个小时后,仍然不清楚 OP 的意思。 - Philippe Leybaert
是的,那是我在提问时犯的错误。我现在已经修改过了。 - sameer karjatkar

6
不是堆栈也不是堆,而是 .data 段。

这取决于全局内存是在应用程序中内联分配还是动态分配的。 - Philippe Leybaert
1
如果内存是动态分配的,它就不是全局的(从全局变量的意义上来说)。 - EFraim
我们正在谈论通过全局变量全局访问的分配内存。实际上,编译器甚至可以选择在堆上分配预分配的内存块,而不是在固定的内存块中分配(如果该块太大)。 - Philippe Leybaert
2
@Philippe - 关键是全局指针所指向的数据不能被视为全局。它甚至可以在程序执行过程中发生变化(不同的函数可能会将全局指针重置为任意位置)。 - EFraim
1
@Philippe:.data 部分也不是仅限于 .EXE。 - EFraim
显示剩余4条评论

5

在C++中,全局声明数据结构既不会消耗堆内存也不会消耗栈内存。实际上,全局变量通常分配在数据段中,该段的大小在整个程序执行期间保持不变。堆和栈通常用于在程序执行期间创建和销毁的变量。

程序内存空间


0

全局对象本身将占用运行时或编译器在执行main之前为其保留的内存,这不是变量运行时成本,因此既不是堆栈也不是堆。

如果对象的构造函数分配内存,则将在堆中进行任何后续的对象分配都将是堆分配。

这取决于全局对象的确切性质,如果它是指针还是整个对象本身是全局的。


-1

全局变量存储在堆上。这是一个特殊情况,因为它们的生命周期与程序相同。


-3
如果您通过new或malloc显式地分配内存,则它将在堆上分配。如果编译器分配内存,则它将在栈上分配。

1
全局内存从不在堆栈上分配。堆栈仅用于本地变量和参数。 - Philippe Leybaert
1
当函数返回时,堆栈变量被“销毁”。 - user128026

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接