我在asp.net网站上寻找内存泄漏。我发现的一个问题是,当不再需要控件时,代码不会释放事件处理程序。我使用了MSDN上显示的处理模式来清理它们,然后调用删除if (disposing)
块中的事件处理程序,因为它们是托管资源,但除非我通过并向每个页面添加析构函数,让他们全部手动处理控件没有什么火,直到终结器清理混乱。这样做会很脆弱,并且在未来相对容易重新引入泄漏;我会更好地忽略关于不接触终结器运行的代码中的非托管对象的约定吗?
// Design pattern for a base class.
public class Base: IDisposable
{
//Implement IDisposable.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
myControl.SomeEvent -= SomeEventHandler;
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
}
// Use C# destructor syntax for finalization code.
~Base()
{
// Simply call Dispose(false).
Dispose (false);
}
}
答案 0 :(得分:2)
asp.net控件何时处理
从不,如果有任何实时参考。
如果您有任何Dispose
个对象,则调用Disposable
方法是最佳做法。如果您只是允许它们超出范围,它们将在第一个垃圾收集周期中添加到终结队列中。并在完成后将在第二个垃圾收集周期中释放内存。如果您可以调用Dispose
方法和SuppressFinalization
,那么最终确定会产生不必要的开销。
另一件事是你的代码示例。拥有Finalize
方法而没有任何非托管代码。如果你看一下Finalize-> Dispose(false)的执行路径,你会注意到它什么也没做。因为只有disposing
处理所有托管对象。因此,如果您没有任何非托管对象,则无需添加Finalize
方法。
只有当该对象没有任何实时引用时(在第一个GC循环中),该对象才会被添加到Finalization Queue并调用Finalize
方法。因此,您有责任取消注册必要的活动。否则Finalize
将永远不会执行,只要有对该对象的引用。
以下是取消注册事件处理程序的一个很好的参考资料。
答案 1 :(得分:1)
您需要触摸它的唯一时间是您希望清洁它现在
或者,如果您要输入创建大量对象的块。
否则 - 让GC决定。
P.S。为什么不使用USING机制?
答案 2 :(得分:1)
只有在垃圾收集器确定它已准备好运行时,才会清理您的对象。通常,如果需要清理非托管资源(如文件句柄等)或外部连接,则只能实现一个dispose。如果您长时间看到这些资源并通过多个集合,那么某些东西可能会在某处继续引用。
使用dispose并没有错,因为我看到的......它并没有真正让你得到任何东西。您正在删除对事件的引用,但是在GC决定收集它们之前,底层对象将保留在堆上。