我们一直在进行大量的内存泄漏分析,并且发现其中一个影响因素是没有删除代理事件导致对象无法足够快地(或有时永远)进行GC。
对于如何在FXCop中编写规则以确保我们从处理程序中删除委托,有人会有任何想法吗?
我刚刚看到this,因此我会向那里询问更多信息。
答案 0 :(得分:3)
你需要更加具体。您无需检查所有事件代理是否已取消订阅,因为在一般情况下,订阅者的生命周期比发布者短。只有当您的订阅者比发布者看起来更长时才会发生内存泄漏,因此有一个引用会阻止GC收集发布者对象。
现在我们需要验证,如果您订阅了一个相对较短的生活对象的事件,您最终会取消订阅。
在这种情况下我可以提出一种启发式方法:分析所有本地变量对象(由当前代码块{}确定范围)和所有显式Dispose的对象。对于这些对象上的每个事件,都会计算您订阅它们的次数以及取消订阅的次数。如果第一个数字更大,则发出警告。
当然这并没有涵盖所有情况,但我想没有静态方法可以涵盖这个问题的所有情况,你需要一些足够好的方法。
我不会在此提及动态分析和代码审查的优势,因为它是一个单独的主题,与问题无关。
答案 1 :(得分:2)
好的,除了实现实际检查的问题(在我看来这与path coverage非常相似,因此不实用) - 这是编写新的FxCop规则的方法:
起初有些文章曾帮我一次:
实施简单的规则没什么大不了的。在您的项目中,您需要一个Rules.xml文件作为嵌入式资源(请参阅here)。您从BaseIntrospectionRule
派生您的课程,并将您的代码添加到Check() - 方法:
public override ProblemCollection Check( TypeNode typeNode )
{
if( type.IsPublic )
{
Problems.Add( new Problem( ... ) );
}
return Problems;
}
我之前做过这个。我希望它仍然如上所述:)
答案 2 :(得分:1)
您是否可以强制规则所有事件订阅都应通过WeakReferences处理?我认为这比分析程序的实际流程更容易实现。
答案 3 :(得分:0)
是否可以安全地假设实现处理程序的对象以某种方式将事件引用回事件?如果是这样的话,你最好再找出如何以另一种方式打破循环。
我们在ASP.NET页面上使用事件处理程序进行了类似的操作。实现处理程序的对象也具有对页面的引用。在尽可能地破坏尽可能多的链接后,少数剩余部分被改为WeakReferences。没有更多的记忆问题!