Существует множество форм утечек:
- Неуправляемые утечки (код, который выделяет неуправляемый код)
- Утечки ресурсов (код, который выделяет и использует неуправляемые ресурсы, такие как файлы, сокеты)
- Увеличенное время жизни объектов
- Неправильное понимание того, как работает управление памятью в GC и .NET
- Ошибки в среде выполнения .NET
Первые два обычно обрабатываются двумя разными частями кода:
- Реализация IDisposable на объекте и удаление неуправляемой памяти / ресурса в методе Dispose
- Реализация финализатора, чтобы гарантировать, что неуправляемые ресурсы освобождаются, когда GC обнаружил, что объект имеет право на коллекцию
Третий, однако, отличается.
Допустим, вы используете большой список, содержащий тысячи объектов, что занимает значительный объем памяти. Если вы будете хранить ссылку на этот список дольше, чем нужно, у вас будет что-то вроде утечки памяти. Кроме того, если вы продолжаете добавлять в этот список, чтобы он периодически увеличивался с увеличением объема данных, а старые данные никогда не использовались повторно, у вас определенно возникает утечка памяти.
Один из источников, которые я часто видел, - это присоединение методов к обработчикам событий, но не забудьте отменить их регистрацию, когда закончите, медленно увеличивая размер обработчика событий и кода для выполнения.
В-четвертых, неправильное понимание того, как работает управление памятью .NET, может означать, что вы смотрите на использование памяти в средстве просмотра процессов и замечаете, что ваше приложение продолжает увеличивать использование памяти. Если у вас есть много и много доступной памяти, GC может работать не так часто, давая вам неправильное представление о текущем использовании памяти, в отличие от отображаемой памяти.
В-пятых, это сложнее, я видел только одну ошибку управления ресурсами в .NET, и на самом деле она была исправлена в .NET 4.0, это было с копированием экрана рабочего стола в образ .NET.
Редактировать : В ответ на вопрос в комментариях, как избежать хранения ссылок дольше, чем необходимо, тогда единственный способ сделать это - просто сделать это.
Позвольте мне объяснить.
Во-первых, если у вас есть долгосрочный метод (например, это может быть обработка файлов на диске, или загрузка чего-либо, или чего-то подобного), и вы использовали ссылку на большую структуру данных в начале метода, до долгосрочную часть, и затем вы не используете эту структуру данных для остальной части метода, тогда .NET, в сборках выпуска (и не работает под отладчиком) достаточно умен, чтобы знать, что эта ссылка, хотя и содержится в переменной, которая технически находится в области видимости, имеет право на сборку мусора. Сборщик мусора действительно агрессивен в этом отношении. В отладочных сборках, работающих под отладчиком, он сохранит ссылку на весь жизненный цикл метода на тот случай, если вы захотите проверить его при остановке в точке останова.
Однако, если ссылка хранится в ссылке на поле в классе, где объявлен метод, это не так уж умно, так как невозможно определить, будет ли оно использовано повторно в будущем или, по крайней мере, очень сложно. Если эта структура данных становится ненужной, вам следует очистить имеющуюся у нее ссылку, чтобы GC позже ее обнаружил.