Любые идеи о том, как написать правило статического анализа (FXCop), чтобы гарантировать удаление делегатов событий


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

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

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

4 7

4 ответа:

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

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

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

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

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

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

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

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

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

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

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

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

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