В настоящее время я отлаживаю большое (очень большое!) Приложение C #, которое содержит утечки памяти. Он в основном использует Winforms для GUI, хотя пара элементов управления сделаны в WPF и размещены в ElementHost. До сих пор я обнаружил, что многие утечки памяти были вызваны тем, что события не были отсоединены (путем вызова - =), и я смог решить эту проблему.
Однако я только что столкнулся с подобной проблемой. Существует класс WorkItem (недолговечный), который в конструкторе регистрируется для событий другого класса, который называется ClientEntityCache (долгоживущий). События никогда не отцеплялись, и в профилировщике .NET я видел, что экземпляры WorkItem поддерживаются, когда они этого не делают, из-за этих событий. Поэтому я решил заставить WorkItem реализовывать IDisposable, и в функции Dispose () я отцепил события следующим образом:
public void Dispose()
{
ClientEntityCache.EntityCacheCleared -= ClientEntityCache_CacheCleared;
// Same thing for 10 other events
}
EDIT
Вот код, который я использую для подписки:
public WorkItem()
{
ClientEntityCache.EntityCacheCleared += ClientEntityCache_CacheCleared;
// Same thing for 10 other events
}
Я также изменил код для отмены регистрации, чтобы не вызывать новый EntityCacheClearedEventHandler.
Конец редактирования
Я сделал вызовы Dispose в надлежащих местах кода, который использует WorkItem, и когда я отлаживаю, я вижу, что функция действительно вызывается, и я делаю - = для каждого события. Но я все еще получаю утечку памяти, и мои WorkItems все еще остаются живыми после удаления, и в профилировщике .NET я вижу, что экземпляры остаются живыми, потому что обработчики событий (такие как EntityCacheClearedEventHandler) все еще имеют их в своем списке вызовов. Я пытался отцепить их более одного раза (несколько - =), чтобы убедиться, что они не были подключены более одного раза, но это не помогает.
У кого-нибудь есть идея, почему это происходит или что я могу сделать, чтобы решить проблему?
Полагаю, я мог бы изменить обработчики событий, чтобы использовать слабых делегатов, но для этого потребовалось бы много возиться с большой кучей устаревшего кода.
Спасибо!
EDIT:
Если это поможет, вот корневой путь, описанный профилировщиком .NET:
Многое указывает на ClientEntityCache, который указывает на EntityCacheClearedEventHandler, который указывает на Object [], который указывает на другой экземпляр EntityCacheClearedEventHandler (я не понимаю, почему), который указывает на WorkItem.