Любые идеи о том, как написать правило статического анализа (FXCop), чтобы гарантировать удаление делегатов события - PullRequest
7 голосов
/ 13 мая 2009

Мы проходили большой анализ утечек памяти и обнаружили, что одним из факторов, способствующих этому, является отсутствие удаления делегатов для событий, из-за чего объекты не могут быть достаточно быстро собраны (или иногда навсегда).

Есть ли у кого-нибудь идеи, как написать правило в FXCop, чтобы гарантировать удаление делегатов из обработчиков?

Я только что видел это , и поэтому я попрошу там больше информации.

Ответы [ 4 ]

3 голосов
/ 12 июня 2009

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

Теперь нам нужно убедиться, что если вы подписываетесь на событие относительно недолговечного объекта, вы в конце концов отмените подписку.

Эвристика, которую я могу придумать в этом случае: проанализировать все объекты локальных переменных (которые ограничены текущим блоком кода {}) и все объекты, которые вы явно удалите. Для каждого события в этих объектах подсчитайте, сколько раз вы подписались на них и сколько раз вы отменили подписку. Если первое число больше, выведите предупреждение.

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

Я не буду упоминать о преимуществах динамического анализа и обзоров кода здесь, поскольку это отдельная тема, не связанная с вопросом.

2 голосов
/ 15 июня 2009

Хорошо, кроме проблемы реализации фактической проверки (на мой взгляд, это очень похоже на покрытие пути и, следовательно, не практично) - вот способ написать новое правило FxCop:

Сначала несколько статей, которые мне однажды помогли:

Реализация простого правила не представляет особой проблемы. В вашем проекте вам нужен файл Rules.xml как встроенный ресурс (см. здесь ). Вы выводите свой класс из BaseIntrospectionRule и добавляете свой код в метод Check () -

public override ProblemCollection Check( TypeNode typeNode )
{
  if( type.IsPublic )
  {
    Problems.Add( new Problem( ... ) );
  }
  return Problems;
}

Я делал это несколько раз назад. Я надеюсь, что это все еще работает как описано:)

1 голос
/ 14 июня 2009

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

0 голосов
/ 13 мая 2009

Можно ли предположить, что объекты, реализующие обработчики, каким-то образом имеют ссылки на объект с событиями? Если это так, то вам лучше понять, как разорвать цикл другим способом.

Некоторое время назад у нас было нечто подобное с обработчиками событий на страницах ASP.NET. Объекты, которые реализовали обработчики, также имели ссылки на страницы. После того, как мы разрушили как можно больше архитектурных ссылок, несколько остатков были заменены на WeakReferences. Больше никаких проблем с памятью!

...