GC 如何与 IEnumerator 一起工作并产生
本文关键字:工作 一起 IEnumerator GC | 更新日期: 2023-09-27 18:34:29
我知道枚举器和yield关键字可用于帮助进行异步/交错操作,因为您可以调用MoveNext()
来运行下一个代码块。
但是,我真的不明白枚举器对象是什么。枚举器作用域使用的内存去哪儿了?如果您不一直MoveNext()
枚举器,它最终会得到 GC 吗?
基本上,我试图降低我的 GC 命中率,因为我可能使用了很多枚举器,而 GC 可能是 Unity 内部的一个问题,特别是由于它使用的旧版本的 Mono。
我试图对此进行剖析,但仍然无法理解它们。我不明白枚举器发生的范围/引用。我也不明白当您从生成的函数创建一个枚举器时,枚举器是否被创建为对象。
以下示例更好地显示了我的困惑:
// Example enumerator
IEnumerator<bool> ExampleFunction()
{
SomeClass heavyObject = new SomeClass();
while(heavyObject.Process())
{
yield return true;
}
if(!heavyObject.Success)
{
yield return false;
}
// In this example, we'll never get here - what happens to the incomplete Enumerator
// When does heavyObject get GC'd?
heavyObject.DoSomeMoreStuff();
}
// example call - Where does this enumerator come from?
// Is something creating it with the new keyword in the background?
IEnumerator<bool> enumerator = ExampleFunction();
while(enumerator.MoveNext())
{
if(!enumerator.Current)
{
break;
}
}
// if enumerator is never used after this, does it get destroyed when the scope ends, or is it GC'd at a later date?
您可能应该阅读枚举器内部帖子。从内部,您可以回答所有这些问题。
速成课程:每个迭代器方法执行都会返回一个新的枚举器对象。局部变量成为字段。
如果没有人再使用该枚举器对象,则它有资格进行收集。此外,出于 GC 目的,局部变量创建的所有引用都会消失。
对于局部变量何时不再是 GC 引用,有一些边缘情况。如果您的枚举器寿命相当短,这无关紧要。
CLR 不知道枚举器是什么。它只是 C# 编译器生成的一个类。
将xanatos的链接拉到这个答案中,因为它是说明性的,他似乎没有发布答案:http://goo.gl/fs4eNo
如果在此之后从未使用枚举器,那么它在以下情况下是否会被销毁 范围结束
正确
收集的资格是没有参考资料。对于 GC 的范围界定,枚举器没有什么特别之处。当枚举器超出范围时,它们以与任何其他类型相同的方式处置/清除。
枚举器的管理方式与所有其他托管实例相同 - 当枚举器超出范围时。因此,如果从未调用MoveNext()
则 GC 会在枚举器超出其范围时删除(或更好地将其标记为删除(。迭代枚举器不会以任何并行方式发生,因此执行和垃圾回收在完成后都会确定和按顺序运行。
在迭代器方法中,yield-return
-stament 根本不是最后一条语句,它只是意味着当调用MoveNext()
时,应该返回当前结果。但是,yield return
后面的所有内容都在调用MoveNext
之后运行,因此您的DoSomeMoreStuff
调用也是如此。
但是,您的heavyObject
具有该方法的范围,因此它与迭代器(其中迭代器是while
循环中的块(一样长。这意味着,如果您的迭代器甚至没有返回任何实例heavyObject
将立即被释放,否则迭代完成后。