如何为在 main() 外部和内部声明的变量分配内存
Posted
技术标签:
【中文标题】如何为在 main() 外部和内部声明的变量分配内存【英文标题】:How memory is allocated for a variable declared outside vs inside main() 【发布时间】:2014-06-16 09:46:15 【问题描述】:我注意到,在处理一些大型数组(如将 1000 乘以 1000)时,如果我在 main() 中声明数组,我的程序会耗尽内存,但如果我在 main() 之外声明数组,这似乎永远不会发生。 ) 即使对于更大的数组。谁能解释一下区别是什么?
【问题讨论】:
Global memory management in C++ in stack or heap? 的可能重复项 【参考方案1】:当您的程序将执行时,它将创建一个进程,该进程将占用内存中的固定内存大小。这个过程包含四个部分,数据部分、代码部分、堆和堆栈。在这四个部分中,数据和代码部分的大小是固定的,而堆栈(存储局部变量、静态数据)和堆(存储动态内存分配的数据)的大小在执行过程中会发生变化。现在,如果您在全局区域的主要方式之外声明变量,那么它将存储在具有固定大小的进程的数据部分中。所以在 main 之外创建非常大的数组会导致数据部分出现问题。如果你将它存储在 main 中,那么它的大小可以由堆栈管理。
【讨论】:
【参考方案2】:你必须决定大块内存应该来自堆(决定动态分配数组)还是来自堆栈(在某个函数中有一个局部变量,当不在范围内时将被释放),在主放置之外全局地址空间中的数据在所有函数之间共享,在 main 之前分配,在 main 完成后(在程序退出时)被释放。
【讨论】:
【参考方案3】:栈的大小约为2-3M,堆的大小与虚拟内存有关,可以很大。你可以这样声明static int num[1000][1000];
【讨论】:
【参考方案4】:在大多数系统上,函数中声明的内存将进入堆栈,堆栈很小并且可能溢出。但是,在main()
之外声明的内存不会。堆栈的大小(和存在)取决于实现 - 尽管我不知道有任何常用的 C++ 系统不存在堆栈。
从技术上讲,在函数内声明的内存具有automatic
存储持续时间,这意味着它在封闭代码块的开头分配,并且在该代码块完成后无效。
在main之外声明的内存有static
的存储期,也就是说它是在程序启动时分配的,在程序的整个生命周期内都有效。
有关存储期限的更多信息,请参阅this link。
如果要在函数中声明大量内存,可以使用分配函数malloc
或new
。 This link 清楚地解释了栈和堆的区别(虽然是关于 C 而不是 C++,但它仍然适用于 C++)。
【讨论】:
不,它不会在堆上。它是静态分配的。 啊,完全正确。我已经更正了帖子和我的记忆:)【参考方案5】:如果它是一个函数的本地函数(main
只是另一个函数),它将进入堆栈。 1000x1000x8 = 800 万字节。这可能大于堆栈大小。不同的编译器可能有不同的大小,但我认为默认是1MB。
全局变量(它们具有静态存储)不是在堆栈上分配,也不是在堆上分配,而是在一个数据段上,其大小在整个程序持续时间内保持不变。
请注意,一个进程不仅有两个内存区域,堆栈和堆。它还有一个代码/文本段,一个用于程序中已初始化静态变量的数据段和另一个用于未初始化静态变量的称为 bss 段的数据段。更多信息请见Anatomy of a Program in Memory。
【讨论】:
【参考方案6】:这是与实施相关的问题。从理论上讲,在与全局作用域相同的函数中应该可以定义一个内存消耗变量。
但实际上,全局范围内的变量将在目标机器代码的数据段中声明,并且有更多的可用空间可以分配。但是,在函数中通常会使用堆栈概念,这有一些限制。
【讨论】:
【参考方案7】:当一个变量在函数中声明时(在你的例子中,main
),它被分配在堆栈上,如果它太大(例如,一个大数组),你会遇到stack overflow。
在所有函数之外定义的变量是静态分配的。它的生命周期一直持续到程序终止。
【讨论】:
这是否意味着您不会遇到所有函数之外的分配堆栈溢出?我不确定这是否是您的意思。 @Human 确实如此。由于数组不在堆栈上,因此您无法通过将其置于全局范围内来获得堆栈溢出。如果在全局范围内声明太大的数组,系统最终会耗尽内存,无法启动应用程序。堆分配也是如此,不可能产生堆栈溢出,但你可以用完堆内存。 @Human 堆栈溢出可能由多种原因引起,在这种情况下,堆栈变量非常大,如果一个变量定义在所有函数之外,那么它不会占用堆栈空间。但是当然其他类型的堆栈溢出仍然是可能的(非常深的递归等)。以上是关于如何为在 main() 外部和内部声明的变量分配内存的主要内容,如果未能解决你的问题,请参考以下文章