Просто на днях я исследовал утечку памяти, которая увеличивалась приложение от ~50MB до ~130MB через менее чем две минуты. Оказывается, что проблема была с классом ConcurrentQueue. Внутренне, класс хранит связанный список массивов. Когда объект исключается из очереди от ConcurrentQueue, индекс в массиве ударен, но объект остается в массиве (т.е. он не устанавливается в NULL). Узел целого массива отбрасывается после того, как достаточно ставит в очередь/исключает из очереди, таким образом, это не технически утечка, но при помещении больших объектов в ConcurrentQueue, это может выйти из-под контроля быстро. Документация не делает примечания этой опасности.
Я задавался вопросом, что другие потенциальные ловушки памяти находятся в Библиотеке базовых классов? Я знаю о Подстроке одну (то есть, если Вы будете называть подстроку и просто держать на результат, то целая строка все еще будет в памяти). Какие-либо другие Вы встретились?
Вы правы. Ошибка находится в методе System.Collections.Concurrent.ConcurrentQueue
.
Если вы посмотрите на этот метод в Reflector, вы увидите следующую строку:
result = this.m_array[low];
После нее должна быть следующая строка:
this.m_array[low] = default(T);
Для справки вы можете увидеть, как это правильно реализовано в методе System.Collections.Generic.Queue
.
Хотя нет прямая утечка памяти или специфическая для .net / BCL проблема с конкатенацией строк (с использованием оператора + =). Это довольно интенсивно загружает ЦП в циклах из-за интенсивного сбора мусора.