我知道枚举器和yield关键字可用于帮助执行异步/交错操作,因为您可以调用MoveNext()
来运行下一个代码块。
但是,我并不真正了解Enumerator对象是什么。使用枚举器范围的内存在哪里?如果您不是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?
答案 0 :(得分:5)
您可能应该阅读枚举器内部帖子。从内部来看,你可以回答所有这些问题。
速成课程:每个迭代器方法执行都返回一个新的枚举器对象。局部变量成为字段。
如果没有人再使用该枚举器对象,则它有资格进行收集。此外,局部变量创建的所有引用都会因GC而消失。
当确切的局部变量停止为GC引用时,存在一些边缘情况。如果您的调查员相当短暂,这并不重要。
CLR不知道枚举器是什么。它只是由C#编译器生成的一个类。
将xanatos的链接拉到这个答案中,因为它的说明并且他似乎没有发布答案:http://goo.gl/fs4eNo
答案 1 :(得分:3)
//如果在此之后从未使用过枚举器,那么它是否会被销毁 范围结束
正确
收集资格没有参考资料。对于GC的范围界定,调查员没有什么特别之处。当调查员以超出任何其他类型的范围时,以同样的方式处理/清除。
答案 2 :(得分:2)
枚举器的管理方式与每个其他托管实例的管理方式相同 - 超出范围时。因此,如果从未调用MoveNext()
,那么当枚举数超出其范围时,GC将删除(或更好地将其标记为删除)。迭代枚举器不会以任何并行方式进行,因此执行和垃圾收集在完成后都会确定性地和连续地运行。
当在迭代器方法中时,yield-return
- stament根本不是最后一个语句,它只是意味着当调用MoveNext()
时,应该返回当前结果。但是,yield return
后面的所有内容都会在调用MoveNext
之后运行,因此您也会调用DoSomeMoreStuff
。
但是heavyObject
具有方法的范围,因此它与迭代器一样长 - 迭代器是while
- 循环中的块。这意味着如果您的迭代器甚至没有返回任何实例heavyObject
将被立即处理,否则迭代完成后。