【发布时间】:2011-11-12 16:49:44
【问题描述】:
作为值类型变量在堆栈中分配内存,而作为引用类型在堆中分配内存。
那么当值类型变量(例如 int i =4;)在引用类型中(例如在类中)声明时,内存是如何分配的。
对于值类型和引用类型,以及引用类型范围内的值类型,.net 中的整体内存分配如何工作。
请解释或提供任何相关链接。
谢谢
【问题讨论】:
标签: c# memory-management
作为值类型变量在堆栈中分配内存,而作为引用类型在堆中分配内存。
那么当值类型变量(例如 int i =4;)在引用类型中(例如在类中)声明时,内存是如何分配的。
对于值类型和引用类型,以及引用类型范围内的值类型,.net 中的整体内存分配如何工作。
请解释或提供任何相关链接。
谢谢
【问题讨论】:
标签: c# memory-management
值类型变量在栈上分配内存,而引用类型在堆上分配内存。
不,这种说法是完全错误的。很多人都相信这一点,但正如您所发现的,这显然是错误的。
当值类型变量
int i = 4;被声明为引用类型的字段时,内存是如何分配的?
很明显,您知道为什么您的第一个陈述是完全错误的。类的整数字段不能在堆栈上分配,因为对象的寿命可能比堆栈帧长。
要了解真正发生的事情,首先你必须意识到有三种种事情:
引用和引用类型的实例完全不同,就像一张包含我的地址和我的实际房子的纸完全不同。
接下来你要了解的是,存储有两种:长期存储和临时存储。长期存储通常称为“堆”,但我更愿意将其简单地视为长期存储。临时存储通常称为“堆栈”,但这也具有误导性,因为当然可能有多个堆栈,也可能有临时存储在寄存器中,等等。
引用类型的实例在长期存储中占用内存。 (有时可以确定引用类型的实例是短暂的,并将其放入临时存储中,但实际上我们不会进行此优化。)
变量是一个存储位置,用于存储值类型的值或引用。
变量的存储位置分配在哪里取决于变量的生命周期。如果变量是已知生命周期短的局部变量,则从临时存储池中分配。如果已知变量的生命周期很长(例如,因为它是闭包的外部变量),那么它将被分配到长期存储池之外。
如果变量是一个类的字段,我们已经知道它的存储来自长期池。如果变量是值类型的字段,则该值类型存储在某处;该字段位于相同的存储空间中。
如果变量是数组元素,则从长期存储池中分配出去;数组是引用类型的实例。
正确理解的关键是不要再相信变量是引用类型还是值类型会影响存储分配位置的神话。那不是真的,从来都不是真的,甚至没有任何意义。
影响变量存储位置的唯一因素是变量的生存时间。短期变量在临时池(堆栈或寄存器)之外分配,而长期变量则在长期存储池(堆)之外分配。
【讨论】:
这就是为什么 Eric Lippert 提醒我们the stack is an implementation detail.
当值类型的实例是引用类型的成员时,是的,它与父对象一起存储在托管堆中。这是一个很好的问题,你应该理解,而不是应该在大多数场景中推动你的设计。
structs 应该是小而简单的数据类型,创建和传递相对便宜。引用类型是您的复杂类型,只需要引用的副本即可传递给方法,但由于在堆上分配,因此当然会带来一些包袱。这是一个很好的follow up post,关于堆栈与堆分配的含义。
有很多参考资料解释了值类型与引用类型的性能影响。您应该全面了解它,并了解大多数情况下,这是一个语义决定,而不是性能决定。
【讨论】:
那么当值类型变量(例如 int i =4;)在引用类型中(例如在类中)声明时,内存是如何分配的。
如果对象位于堆上,则意味着它的所有成员变量都在堆中。
【讨论】:
这是一个不错的article。
顺便说一句:并非总是在堆栈中出现值 - 它可能在堆中结束。
【讨论】: