结构体总是分配堆栈还是有时分配堆?
我的印象是,在 C# 中,结构元素是在堆栈上分配的,因此从创建它们的方法返回时会消失。但是如果我将结构值放入列表中并返回它会发生什么?元素得以幸存。 结构实例有时会分配在堆上吗?
internal struct Stru
{
public int i;
}
internal class StruTry
{
public List<Stru> Get(int max)
{
var l = new List<Stru>();
for (int i = 0; i < max; i++)
l.Add(new Stru {i=i});
return l;
}
}
代码打印 0, 1, 2
[Test]
public void T()
{
var ll = new StruTry().Get(3);
foreach (var stru in ll)
Console.WriteLine("* "+ stru.i);
}
I was of the impression that in C#, struct elements are allocated on the stack and thus disappear when returning from a method in which they were created. But what happens if I place the struct-values in a list and return that? The elements survives. Are struct instances sometimes allocated on the heap?
internal struct Stru
{
public int i;
}
internal class StruTry
{
public List<Stru> Get(int max)
{
var l = new List<Stru>();
for (int i = 0; i < max; i++)
l.Add(new Stru {i=i});
return l;
}
}
code printing 0, 1, 2
[Test]
public void T()
{
var ll = new StruTry().Get(3);
foreach (var stru in ll)
Console.WriteLine("* "+ stru.i);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
首先,阅读 Eric Lippert 发表的这篇文章 堆栈是一个实现细节。跟随关于值类型的真相。
至于你的具体问题
是的,它们有时分配在堆上。有很多关于何时可以在堆上分配它们的示例。如果它们被装箱,或者它们是类中的字段,或者它们是数组的元素,或者它们是已封闭的值类型变量的值,等等。
您正在以正确的方式思考这一点,这是可以分配值类型的要点之一。有关更多详细信息,请参阅我在关于值类型的真相中提到的第二篇文章。但请记住堆栈是一个实现细节。关键的一点是你真的不需要关心这些东西。您应该关注值类型和引用类型之间的语义差异。
First, read this post from Eric Lippert on The Stack is an Implementation Detail. Follow it with The Truth about Value Types.
As for your specific question
Yes, they are sometimes allocated on the heap. There are lots of examples of when they could be allocated on the heap. If they are boxed, or if they are fields in a class, or if they are elements of an array, or if they are the value of a variable of value type that has been closed over, etc.
You're thinking about this the right way, and this is one of the salient points on where a value type might be allocated. See the second post that I referred to on The Truth About Value Types for more details. But just keep The Stack is an Implementation Detail in mind. The key takeaway is that you really don't need to concern yourself with this stuff. You should be concerned with the semantic difference between value types and reference types.
结构就像
int
。如果你有一个本地int
,它通常会在堆栈上,如果你有一个int
列表,它们会直接存储在列表的内部数组中,即在堆上。结构体的行为方式相同。Structs are like
int
s. If you have a localint
, it will generally be on the stack, if you have a list ofint
s, they are stored directly in the list's internal array, which is on the heap. Structs behave the same way.从技术上讲,添加到“列表”的值不是相同的值,它们是基于值的副本。例如,如果您修改原始文件,这些更改将不会传递到列表中的副本中。此外,“List”返回指定索引处的值的副本。这意味着如果结构是可变的并且您修改从“List”返回的值,则
List
中的值将保持不变。数组的情况并非如此,因为数组索引提供对实际变量的访问。Technically the values added to the 'List' are not the same values, they are value based copies. If, for example, you modify the original, those changes will not be carried to the copy in the list. Also, 'List' returns a copy of the value at the indicated index. This means if the struct is mutable and you modify the value returned from the 'List', then the value in the
List<t>
will remain unchanged. This is not the case with arrays, as the array index provides access to the actual variable.有时可以在堆上分配所有类型。除此之外,堆/堆栈是 CLR 的实现细节,而不是 C# 规范中的实现细节,因此您不应该依赖这些东西。请参阅此处 关于这个主题的好博客文章。
All types can sometime be allocated on the heap. Besides which, heap/stack is an implementation detail of the CLR and not in the C# spec, so you shouldn't ever rely on such things. See here for a good blog post on this subject.
据我所知...
值类型的位置取决于它们的声明位置。方法变量被分配、存储在堆栈中,并在堆栈帧中执行方法后被删除。声明为引用类型一部分的值类型存储在封闭类型结构内的堆上。
如果我错了请告诉我!
From what I remember...
The location of value types depends on where they are declared. Method variables are allocated, stored on the stack and removed after execution of the method in the stack frame. Value types declared as part of a reference type are stored on the heap within the structure of the enclosing type.
Let me know if I am wrong!
结构类型的存储位置(变量、字段、参数、数组槽等)保存结构的公共和私有字段。如果该存储位置位于堆栈上,则该结构的字段也将位于堆栈上。如果它位于另一个类或结构中,则该结构的字段将存储为该其他类或结构实例的一部分。
类类型的存储位置保存对完整类对象的引用,该对象始终要么 (1) 存储在与保存引用的存储位置完全独立的位置,要么 (2) em> 存储位置是其字段的类对象。
A storage location (variable, field, parameter, array slot, etc.) of struct type holds the struct's public and private fields within it. If that storage location is on the stack, the struct's fields will be on the stack. If it is within another class or struct, then the struct's fields will be stored as part of that other class or struct instance.
A storage location of class type holds a reference to a complete class object which is always either (1) stored somewhere completely separate from the storage location holding a reference, or (2) the class object of which that storage location is a field.
使用 C# 7.2,您可以使用
ref
关键字声明始终在堆栈上分配且不会放入堆中的结构:但它有很多限制。
所有详细信息均在官方文档中: https ://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/ref-struct
With C# 7.2 you can declare struct which is always allocated on stack and will not be put into heap - using
ref
keyword:But it has many limitations.
All details are in official docs: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/ref-struct
还有另一个我在上面的评论中没有看到的例子:如果一个结构体是静态字段,那么它也将存储在堆中。
There is also another example that I did not see in the above comments: if a struct is a static field then also it will be stored in the heap.