Ответ
Утечка памяти в управляемом коде C# — это ситуация, когда объекты остаются в памяти, потому что на них существуют корневые ссылки, хотя логически они уже не нужны. GC не может их собрать.
Классический пример: неправильная работа с событиями
public class EventPublisher
{
public event EventHandler SomethingHappened;
}
public class EventSubscriber
{
private string _data;
public EventSubscriber(EventPublisher publisher, string data)
{
_data = data;
// ПОДПИСКА: publisher теперь содержит ссылку на этот экземпляр Subscriber
publisher.SomethingHappened += OnSomethingHappened;
}
private void OnSomethingHappened(object sender, EventArgs e)
{
Console.WriteLine(_data);
}
// ОТПИСКИ НЕТ! -> УТЕЧКА
}
// Использование:
var publisher = new EventPublisher();
while (true)
{
var subscriber = new EventSubscriber(publisher, "leaking object");
// После выхода из области видимости ссылка 'subscriber' теряется,
// но publisher.SomethingHappened всё ещё держит делегат, ссылающийся на метод объекта.
// Объект subscriber будет жить, пока жив publisher.
}
Другие частые причины утечек:
- Статические коллекции:
public static class Cache { public static List<HeavyObject> GlobalCache = new List<HeavyObject>(); } // Объекты, добавленные в GlobalCache, никогда не будут собраны GC. - Таймеры и колбэки: Объект, зарегистрированный как колбэк в
System.Threading.Timer, будет удерживаться в памяти. - Неуправляемые ресурсы: Классы, реализующие
IDisposable(файлы, соединения с БД, графические ресурсы), но не освобождаемые явно.
Диагностика и решение:
- Инструменты: Используйте Memory Profiler в Visual Studio, dotMemory от JetBrains или PerfView.
-
Решение для событий: Реализуйте
IDisposableв подписчике и отписывайтесь.public class EventSubscriber : IDisposable { private EventPublisher _publisher; public EventSubscriber(EventPublisher publisher) { _publisher = publisher; _publisher.SomethingHappened += OnSomethingHappened; } public void Dispose() { _publisher.SomethingHappened -= OnSomethingHappened; // КРИТИЧНО } } - Для кэшей: Используйте
WeakReferenceили готовые реализации (MemoryCacheс политикой вытеснения).