Rozumiem, że moduły wyliczające i słowo kluczowe yield mogą być użyte do pomocy w asynchronicznych/przestawionych operacjach, ponieważ można wywołać MoveNext()
, aby uruchomić następny blok kodu.Jak działa GC z IEnumeratorem i wydajnością?
Jednak tak naprawdę nie rozumiem, co to jest obiekt Enumerator. Skąd bierze się pamięć w użyciu zakresu modułu wyliczającego? Jeśli nie wykonasz w pełni Enumeratora, czy ostatecznie otrzymasz GC?
Zasadniczo staram się nie dopuścić do spadku wartości GC, ponieważ potencjalnie używam wielu enumeratorów, a GC może być problemem w Unity, szczególnie ze względu na starszą wersję Mono, której używa.
Próbowałem profilować to, ale nie mogę jeszcze owinąć ich głową. Nie rozumiem zakresu/odniesienia, które ma miejsce w przypadku enumeratorów. Nie rozumiem też, czy enumeratory są tworzone jako obiekty, gdy tworzy się je z funkcji, która daje.
Poniższy przykład pokazuje mój zamieszanie lepiej:
// 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?
Kompilator przepisuje metodę modułu wyliczającego i przenosi kod do klasy o niewypowiedzianej nazwie. Ta klasa implementuje automat stanów, w którym zmienne lokalne stają się polami klasy, pozwala na ponowne wprowadzanie metody MoveNext() bez utraty stanu. Odwołanie do interfejsu IEnumerator jest w rzeczywistości odniesieniem do obiektu tej klasy. Wszystko mruga w nieskończoność, gdy odwołanie jest zbierane, kwalifikuje się do GC-ed, gdy tylko twój kod opuści pętlę foreach. –
Przykład tego, co powiedział Hans: http://goo.gl/fs4eNo – xanatos
OK, dziękuję. To nie robi tego, czego się spodziewałem. Czy to oznacza, że Enumeratory są dość ciężkie w porównaniu do tradycyjnych metod? Próbuję utrzymać GC w dół, ale wydaje się, że zamierzam utworzyć nowe śmieci za każdym razem, gdy uruchamiam nowy moduł wyliczający (i mam wiele modułów wyliczających). – mGuv