当值类型从集合中删除时,什么时候会发生这种情况?
假设我有一些像这样的简单struct
:
public struct WeightedInt {
public int value;
public double weight;
}
那么假设我有这个结构的实例集合:
List<WeightedInt> weightedInts = new List<WeightedInt>();
据我了解值类型与引用类型,值类型在堆栈上分配,因此值类型一旦实例化该对象的函数终止,该对象就会从内存中清除。这意味着在以下代码中:
void AddWeightedIntToList(int value, double weight) {
WeightedInt wint = new WeightedInt();
wint.value = value;
wint.weight = weight;
weightedInts.Add(wint);
}
局部变量 wint
的副本被添加到weightedInts
,而局部变量本身 AddWeightedIntToList
完成后,em> 将从内存中删除。
首先:这是正确的吗?
其次,这个 wint
的副本存储在哪里?它不能在堆栈上,因为一旦函数完成它就会消失(对吗?)。这是否意味着副本与weightedInts 一起存储在堆上?删除后是否会被垃圾回收,就好像它是引用类型的实例一样?
这个问题当然有可能在某篇文章中得到回答,在这种情况下,该文章的链接将是一个完全可以接受的答案。我只是没有运气找到它。
Suppose I have some simple struct
like this:
public struct WeightedInt {
public int value;
public double weight;
}
Then let's say I have a collection of instances of this structure:
List<WeightedInt> weightedInts = new List<WeightedInt>();
As I understand value types versus reference types, value types are allocated on the stack, so a value type object is cleared from memory once the function instantiating said object terminates. This means that in the following code:
void AddWeightedIntToList(int value, double weight) {
WeightedInt wint = new WeightedInt();
wint.value = value;
wint.weight = weight;
weightedInts.Add(wint);
}
a copy of the local variable wint
is added to weightedInts
whereas the local variable itself is removed from memory after AddWeightedIntToList
is completed.
First of all: is this correct?
Secondly, where does this copy of wint
get stored? It can't be on the stack, since then it would be gone once the function completed (right?). Does this mean that the copy is stored on the heap along with weightedInts
? And is it garbage collected after being removed, as if it were an instance of a reference type?
It's certainly possible that this question is answered in an article somewhere, in which case, a link to that article would be a totally acceptable answer. I just haven't had any luck finding it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
是的。一旦范围结束,原件就会“消失”。
您的
List
实例在堆上创建一个数组。当您将其“添加”到列表时,您正在为该数组的一部分分配值类型的副本。该值作为数组的一部分保存在堆上(List 类的内部)。当您的weightedInts成员超出范围时,它将变得无根,并且有资格被垃圾收集。此后的某个时刻,GC 将运行,并释放与其内部数组关联的内存,从而释放与 wint 副本关联的内存。
编辑:
此外,当您调用时:
会发生一些事情(使用
List
)。首先,该列表查找等于 wint 的值类型的第一个实例的索引。然后它调用 RemoteAt(index)。
RemoveAt(index) 方法基本上标记内部大小小一号,然后检查要删除的索引。如果它位于列表的中间,它实际上使用 Array.Copy 将所有值类型实例复制到一个元素上,以“缩小”列表。然后它将数组末尾的内存清零。
数组本身不会收缩,因此删除元素不会释放任何内存。如果您想回收此内存(甚至使其符合 GC 释放的条件),则需要调用
List
。TrimExcess()。Yes. The original is "gone" once the scope ends.
Your instance of
List<WeightedInt>
creates an array on the heap. You're assigning a portion of that array a copy of your value type when you "add" it to the list. The value is saved on the heap, as part of an array (internal to the List class).When your weightedInts member goes out of scope, it will become unrooted, and eligible to be garbage collected. At some point after that, the GC will run, and will release the memory associated with it's internal array, thereby freeing the memory associated with your copy of wint.
Edit:
Also, when you call:
A few things happen (with
List<T>
).First, the list finds the index of the FIRST instance of your value type that equals wint. It then calls RemoteAt(index).
The RemoveAt(index) method basically marks that the internal size is one smaller, then checks the index you're removing. If it's in the middle of the list, it actually copies ALL of the value type instances up one element using Array.Copy, to "shrink" the list. It then zeros out the memory at the end of the array.
The array itself doesn't shrink, so no memory is released by removing elements. If you want to reclaim this memory (or even make it eligible for freeing by the GC), you need to call
List<T>
.TrimExcess().值类型总是在堆栈上分配是一个常见的误解。
您刚刚展示的示例是在堆上分配值类型的完美示例。
It is a common misconception that value types are always allocated on the stack.
The example you just showed is a perfect example of value types getting allocated on the heap.