Почему и как избежать утечек памяти в обработчике событий? - PullRequest
146 голосов
/ 24 декабря 2010

Я только что понял, прочитав некоторые вопросы и ответы по StackOverflow, что добавление обработчиков событий, использующих += в C # (или, я полагаю, другие языки .net), может вызывать общие утечки памяти ...

В прошлом я много раз использовал подобные обработчики событий и никогда не понимал, что они могут вызвать или вызвали утечки памяти в моих приложениях.

Как это работает (имеется в виду, почему это на самом делевызвать утечку памяти)?Как я могу решить эту проблему?Достаточно ли использовать -= для одного и того же обработчика событий?Существуют ли общие шаблоны проектирования или лучшие практики для обработки подобных ситуаций?Пример: как я должен обрабатывать приложение, которое имеет много разных потоков, используя много разных обработчиков событий для вызова нескольких событий в пользовательском интерфейсе?

Есть ли какие-нибудь хорошие и простые способы эффективно контролировать это в уже построенномбольшое приложение?

Ответы [ 3 ]

182 голосов
/ 24 декабря 2010

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

Если издатель живет дольше, чем подписчик, он будет поддерживать жизнь подписчика, даже если нет других ссылок на подписчика.

Если вы отмените подписку на событиес равным обработчиком, тогда да, это удалит обработчик и возможную утечку.Однако, по моему опыту, это на самом деле редко является проблемой - потому что, как правило, я нахожу, что издатель и подписчик в любом случае имеют примерно одинаковое время жизни.опыт это довольно чрезмерно раскручен.Конечно, ваш пробег может отличаться ... вам просто нужно быть осторожным.

12 голосов
/ 24 декабря 2010

Да, -= достаточно, однако, может быть довольно сложно отслеживать каждое назначенное событие, когда-либо. (подробнее см. пост Джона). Что касается шаблона проектирования, взгляните на шаблон слабого события .

3 голосов
/ 24 декабря 2010

Событие действительно является связанным списком обработчиков событий

Когда вы делаете + = новый EventHandler для события, на самом деле не имеет значения, была ли эта конкретная функция добавлена ​​в качестве прослушивателя ранее, она получитдобавляется один раз за + =.

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

См. Здесь

и MSDN ЗДЕСЬ

...