C # Невозможно очистить память большой универсальной коллекции - PullRequest
4 голосов
/ 29 марта 2011

Я помещаю 2 очень больших набора данных в память, выполняю объединение, чтобы отфильтровать подмножество из первой коллекции, а затем пытаюсь уничтожить вторую коллекцию, поскольку она использует приблизительно 600 МБ оперативной памяти моей системы. Проблема в том, что код ниже не работает. После запуска приведенного ниже кода цикл foreach запускается и занимает около 15 минут. За это время объем памяти НЕ сокращается с 600 МБ +. Я делаю что-то не так?

List<APPLES> tmpApples = dataContext.Apples.ToList(); // 100MB
List<ORANGES> tmpOranges = dataContext.Oranges.ToList(); // 600MB

List<APPLES> filteredApples = tmpApples
    .Join(tmpOranges, apples => apples.Id, oranges => oranges.Id, (apples, oranges) => apples).ToList();
tmpOranges.Clear();
tmpOranges = null;
GC.Collect();

Обратите внимание, я позже повторно использую tmpApples, поэтому я не очищаю его сейчас ..

Ответы [ 6 ]

5 голосов
/ 29 марта 2011

Несколько вещей, на которые стоит обратить внимание:

  • Если ваш dataContext не может быть очищен / собран мусором, то вполне может сохраняться ссылки на множество объектов
  • Вызов Clear() и тогда установка переменной на ноль не имеет смысла, если вы действительно ничего не делаете со списком.GC может определить, когда вы больше не используете переменную, почти во всех случаях.
  • Предположительно, вы судите, сколько памяти зарезервировал процесс;Я не думаю, что CLR фактически вернет память операционной системе, но память, освобожденная сборщиком мусора, будет доступна для дальнейшего использования в CLR.(РЕДАКТИРОВАТЬ: Согласно комментариям ниже, возможно, что CLR освобождает области кучи больших объектов, но я не знаю точно.)
5 голосов
/ 29 марта 2011

Очистка, аннулирование и сбор едва ли когда-либо имеют (положительный) эффект.ГХ автоматически обнаружит, когда на объекты больше не ссылаются.Более того, до тех пор, пока выполняется операция Join, ссылки на коллекции tmpApples и tmpOranges даются вместе со всеми их объектами.Поэтому их нельзя собирать.

Лучшим решением было бы сделать фильтр в базе данных:

// NOTE That I removed the ToList operations
IQueryable<APPLE> tmpApples = dataContext.Apples;
IQueryable<ORANGE> tmpOranges = dataContext.Oranges;

List<APPLES> filteredApples = tmpApples
    .Join(tmpOranges, apples => apples.Id, 
       oranges => oranges.Id, (apples, oranges) => apples)
    .ToList();
1 голос
/ 29 марта 2011

Предполагая, что это проблема кучи больших объектов, вы можете попытаться не получить все яблоки одновременно, а вместо этого получить их в «пакетах».Поэтому вместо вызова

List<APPLE> apples = dataContext.Apples.ToList()

вместо этого попробуйте сохранить яблоки в отдельных списках

int packetSize = 100;
List<APPLE> applePacket1 = dataContext.Apples.Take(packetSize);
List<APPLE> applePacket2 = dataContext.Applies.Skip(packetSize).Take(packetSize);

Помогает ли это?

1 голос
/ 29 марта 2011

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

Вы должны избавиться от DataContext, как только закончите.


UPDATE

Хорошо, вы, вероятно, стали жертвой проблемы с большими объектами .

0 голосов
/ 29 марта 2011

Единственное, что вы делаете неправильно, это явно вызывает сборщик мусора.Вам не нужно этого делать (на самом деле, вы не должны), и, как говорит Стивен, вам не нужно ничего делать с коллекциями, в любом случае они просто уйдут - в конце концов.

Если вы 'Речь идет о производительности 15-минутного цикла foreach, возможно, именно этот цикл вы должны опубликовать.Вероятно, это не связано с использованием памяти.

0 голосов
/ 29 марта 2011

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

РЕДАКТИРОВАТЬ: также имейте в виду, что версия отладки будет задерживать сбор локальных переменных, на которые больше нет ссылок для более легкого исследования.

...