【问题标题】:When does a space for a variable get allocated on the stack?何时在堆栈上分配变量空间?
【发布时间】:2011-08-04 06:03:12
【问题描述】:

在声明或初始化期间是否分配了空间:

int c; // here

c = 5; // or here

【问题讨论】:

  • 可能两者都不是。我认为它必须在输入包含方法时分配。
  • 你怎么知道它在堆栈上?
  • @lukas 因为我认为他没有使用new 关键字,它是值类型而不是引用类型
  • 局部变量存在于堆栈中。他们引用的对象可能存在于堆中。
  • @David Heffernan:如果局部变量存在于寄存器中,则它们不会存在于堆栈中。

标签: c#


【解决方案1】:

何时在堆栈上分配变量空间?

您的问题假定变量的存储空间是在堆栈上分配的。不必如此。你刚才说“int a;”没有指明它是局部变量还是字段,也没有指明其他重要信息,例如局部变量是否是匿名函数的封闭局部,或者该块是否是迭代器块。在许多情况下,变量不会消耗堆栈空间,因为变量不是短期存在的。

假设这个变量是一个短暂的局部变量。它可能仍然不在堆栈上。它可能已注册,特别是如果抖动知道它位于具有大量未使用寄存器的体系结构上。

假设这个变量是一个短暂的局部变量并且jitter没有选择注册它,那么堆栈空间是什么时候分配的?

好吧,再一次,您假设抖动正在使用堆栈作为临时池;尽管这是一种方便的数据结构,但抖动的范围很广。临时池可以在堆外分配,也可以有多个栈;一些架构支持将数据堆栈与调用堆栈分离,以防止堆栈粉碎攻击。

假设变量是一个短暂的局部变量并且jitter选择不注册它并且临时池在调用堆栈上,什么时候分配它的堆栈空间?

现在这取决于您所说的“已分配”是什么意思。整个百万字节的堆栈都保留在虚拟内存系统中并积极提交,因此答案是“一旦创建线程,就会为该线程中将要进入堆栈的所有内容分配堆栈空间,并保持已分配。”当然,它仍然在页面文件中分配。在页面错误将其从磁盘上的页面文件中引入之前,该堆栈不会移动到硬件 (RAM) 中。

如果您要问的是“堆栈指针何时发生碰撞,以便有专门用于此局部变量的堆栈空间”,那么答案通常是“一旦控制进入方法”。这样做当然会触发我刚才提到的页面错误。

我很想知道你为什么在乎。有什么区别?

【讨论】:

  • 您描述它何时被保留。何时分配的问题是否有意义?
  • @David:你说得对,我的术语很草率。我会尽量澄清文本。这是一个令人困惑的问题。
  • 而且即使c存储在栈上,如果可以重用另一个本地的空间,也可能不会为其分配空间。
  • @Eric,感谢您的回复。回答你的两个问题。我不在乎,我只是好奇。让我感到困惑的一件事是,为什么当我观看专业人士解释值类型和引用类型的视频时,他们总是说值类型是在堆栈上分配的,而引用类型是在堆上分配的?
  • @Eric,好评论,我现在比以前有了更好的理解。遗憾的是,这是面试官认为他们有正确答案的面试问题之一。
【解决方案2】:

首先,为了消除每次值类型仅在堆栈内存上分配的混淆,请阅读以下链接。

引用以下文章:

“人们将值类型和引用类型之间的区别解释为“值类型在堆栈上,引用类型在堆上”,引起了很多混乱。这完全是不真实的(如前所述)和这篇文章试图在某种程度上澄清问题。”

memory allocation of value types and reference types in .net framework

http://www.yoda.arachsys.com/csharp/memory.html

http://msdn.microsoft.com/en-us/magazine/cc163791.aspx

【讨论】:

  • 感谢您的链接。他们很有帮助。
【解决方案3】:

堆栈在线程创建时分配,然后按需扩展,可能会因堆栈溢出而终止。

【讨论】:

  • 显然在创建线程时没有分配堆栈内存。好吧,你每天都能学到新东西!
  • 您的答案是正确的,但表明在虚拟内存系统中保留和提交页面之间存在混淆。在 win32 中,线程的创建会立即保留一百万个连续字节的堆栈页。这些页面由保护页面限制,这些页面在命中时会抛出堆栈异常。在非托管代码中,随着堆栈的增长,堆栈空间会自动扩展到提交 保留 虚拟内存页面。在托管代码中,页面的提交更加积极。请记住,保留页面和提交页面是有区别的;不要混淆他们。
  • @eric 你说得对,我对保留、提交等的理解很差。那么我认为在创建线程但按需提交时保留堆栈?更积极地提交托管堆栈是什么意思?
  • Joe Duffy 比我描述得更好。 bluebytesoftware.com/blog/2007/03/10/…。 (顺便说一句,我惊讶地发现我们这样做了;我是直到最近才意识到这种奇怪的人之一。)
  • @eric 确实看起来很奇怪。非常感谢您分享您的知识。然而,阅读那篇文章会更加敏锐地意识到我对虚拟内存的了解不够。总是有更多的东西要学!
【解决方案4】:

编辑:啊,我现在看到这是专门引用堆栈内存。我的答案涉及堆内存。不过,我会为后代保留它。

我相当肯定它是在初始化期间,就好像你有一个对象,比如

IEnumerable<String> myVariable;

你可以这样做:

myVariable = new List<String>();

你还可以这样做:

myVariable = new Stack<String>();

更重要的是,您可以让自己的类充满大量需要大量内存的元数据,只要您正确实现了 IEnumerable,您就可以做到:

myVariable = new MyIEnumerableClass<String>();

因此,(在一般意义上)在变量初始化之前,没有办法真正知道需要多少内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-19
    • 2012-12-26
    • 2013-09-26
    • 2010-11-09
    • 2012-01-18
    • 2021-04-08
    相关资源
    最近更新 更多