сборка мусора в запросе linq - PullRequest
1 голос
/ 01 июля 2010

У меня есть вопрос о том, как сборка мусора может быть обработана в запросе linq. Предположим, мне дан список запросов для обработки. Каждый запрос генерирует очень большой набор данных, но затем применяется фильтр, чтобы хранить только критические данные от каждой запрошенной нагрузки.

//Input data
List<request> requests;
IEnumerable<filteredData> results = requests.Select(request => Process(request)).Select(data => Filter(data));

Итак, я знаю, что запрос откладывается для каждого элемента данных до тех пор, пока не будет запрошен каждый отфильтрованный элемент данных, и это хорошо. Но сохраняется ли эта средняя интенсивная память часть, пока перечисление не будет завершено?

Я надеюсь, что случится так, что каждый элемент данных может быть собран мусором, как только он пройдет стадию фильтрации, таким образом, убедившись, что у меня достаточно памяти для обработки всего списка. Так ли это, или перечислимое среднее сохраняет все до тех пор, пока не закончится весь запрос? Если да, то есть ли способ решить эту проблему?


примечание: функция Process () генерирует данные, интенсивно использующие память ... вот что меня беспокоит

Ответы [ 3 ]

3 голосов
/ 01 июля 2010

Сборщик мусора довольно агрессивен в .NET и может очищать промежуточные объекты когда на них больше нет ссылок, даже внутри циклов. Фактически, в некоторых случаях он очищает объект, на который все еще ссылаются, если он видит, что к нему больше никогда не будет доступа.

Запуск этого кода показывает, что объекты очищаются довольно быстро и не зависают до тех пор, пока запрос не завершится (чего он никогда не делает):

public class MyClass1 { ~MyClass1() { Console.WriteLine("Cleaned up MyClass1"); } }
public class MyClass2 { ~MyClass2() { Console.WriteLine("Cleaned up MyClass2"); } }

public class Program
{
    static IEnumerable<MyClass1> lotsOfObjects()
    {
        while (true)
            yield return new MyClass1();
    }

    static void Main()
    {
        var query = lotsOfObjects().Select(x => foo(x));
        foreach (MyClass2 x in query)
            query.ToString();
    }

    static MyClass2 foo(MyClass1 x)
    {
        return new MyClass2();
    }
}

Результат:

Cleaned up MyClass1
Cleaned up MyClass1
Cleaned up MyClass1
Cleaned up MyClass2
Cleaned up MyClass2
Cleaned up MyClass1
Cleaned up MyClass2
etc...
3 голосов
/ 01 июля 2010

Пока возвращаемые значения Process(...) и Filter(...) не содержат никаких ссылок на "большие элементы данных", используемые внутри, тогда память, используемая в этом процессе, должна стать необработанной и стать кандидатом в GC после каждого элемента обрабатывается.

Это не значит, что он будет собран, только то, что он будет кандидатом. Если давление памяти становится высоким, GC, скорее всего, будет его собирать.

0 голосов
/ 01 июля 2010

Сложно ответить на ваш вопрос, поскольку то, что вы опубликовали, на самом деле не скомпилируется (Select создает IEnumerable<T>, но вы присваиваете его List<T>. Предполагая, что функция Filter(data) возвращаетfilteredData, вам нужно будет вызвать ToList() в запросе, чтобы сохранить его в results).

requests, как я полагаю, уже заполнен данными.Этот список будет следовать обычным правилам сборки мусора.Я предполагаю, что то, что вас беспокоит, является результатом функции Process.Я не могу точно сказать, что произойдет, потому что я также не знаю, что делает ваша функция Filter.Если результат функции Filter не будет содержать ссылку на ее параметр (другими словами, результат функции Process), то объекты, созданные с помощью Process, будут полностью вне области после завершениязапрос и будет следовать обычным правилам сборки мусора.

Имейте в виду, что эти правила определяют приемлемость для сбора.Ни один объект не гарантированно будет собран в течение срока действия вашего приложения.Результаты, однако, будут иметь право, поэтому GC будет способен собирать их.

...