当asp.net控件被销毁时

17 浏览
0 Comments

当asp.net控件被销毁时

我正在调查一个asp.net网站中的内存泄漏问题。我发现一个问题是,当不再需要控件时,代码没有释放事件处理程序。我按照MSDN上显示的disposing模式进行清理,并将删除事件处理程序的调用放在if (disposing)块中,因为它们是托管资源。但是,除非我为每个页面添加析构函数并手动处理控件,否则直到终结器清理掉这个混乱之前,没有任何操作被执行。以这种方式进行操作会很脆弱,并且在将来重新引入泄漏可能会相对容易;那么,我最好忽略在由终结器运行的代码中不操作非托管对象的约定吗?\n

// 一个基类的设计模式。
public class Base: IDisposable
{
   // 实现IDisposable接口。
   public void Dispose() 
   {
     Dispose(true);
     GC.SuppressFinalize(this); 
   }
   protected virtual void Dispose(bool disposing) 
   {
      if (disposing) 
      {
         myControl.SomeEvent -= SomeEventHandler;
         // 释放其他状态(托管对象)。
      }
      // 释放自己的状态(非托管对象)。
      // 将大字段设置为null。
   }
   // 使用C#析构函数语法进行终结器代码编写。
   ~Base()
   {
      // 简单地调用Dispose(false)。
      Dispose (false);
   }
}

0
0 Comments

当使用ASP.NET控件时,控件的生命周期和资源的释放是一个重要的问题。ASP.NET控件的释放时间是由垃圾回收器决定的。一般来说,只有在需要清理非托管资源(如文件句柄等)或外部连接时,才需要实现dispose方法。如果在多个垃圾回收过程中仍然看到这些资源存在很长时间,那么可能有某个地方还保持了对这些资源的引用。

使用dispose方法并没有错,但实际上并没有什么作用。虽然你将对事件的引用释放了,但底层对象仍然会保留在堆上,直到垃圾回收器决定回收它们。

解决方法是确保在不需要控件时及时将其销毁。可以使用以下方法来释放ASP.NET控件:

1. 在页面或用户控件的生命周期方法(如Page_Load或PreRender)中手动调用控件的Dispose方法。

2. 使用using语句来包装控件的实例,以确保在使用完毕后自动调用Dispose方法。

下面是一个示例代码:

protected void Page_Load(object sender, EventArgs e)
{
    MyControl control = new MyControl();
    // 使用控件
    // ...
    // 在页面加载完成后手动调用控件的Dispose方法
    control.Dispose();
}

或者使用using语句:

protected void Page_Load(object sender, EventArgs e)
{
    using (MyControl control = new MyControl())
    {
        // 使用控件
        // ...
    }
}

通过及时调用Dispose方法或使用using语句,可以确保ASP.NET控件在不再需要时能够及时释放资源,从而提高系统的性能和可靠性。

0
0 Comments

asp.net控件何时被销毁?

当你想要立即清除它时。

或者,当你要进入一个创建大量对象的块时。

否则 - 让GC决定。

为什么不使用USING机制?

我参考了George Stocker在这里的回答,他说事件需要被显式释放以避免内存泄漏:stackoverflow.com/questions/3405557/…

我不能使用USING,因为我从未在C#中显式创建控件。除了在定义它们的文件中,它们在.aspx文件中的使用行:<cc1:MyControl ID="MyControl" runat="server" />和在表单的.designer.cs文件中对应的行,没有其他对它们的引用。

0
0 Comments

当asp.net控件没有活动引用时,会被释放。如果你有任何可释放的对象,最佳实践是调用Dispose方法。如果你只是允许它们超出范围,它们将在第一个垃圾回收周期中添加到终结队列中,并在第二个垃圾回收周期中释放内存。如果可以调用Dispose方法和SuppressFinalization,那么终结是一种不必要的开销。

另外,在你的代码示例中,有一个Finalize方法,但没有任何非托管代码。如果你查看Finalize->Dispose(false)的执行路径,可以注意到它什么都不做。因为所有托管对象只有在disposing时才会处理。因此,如果没有任何非托管对象,添加Finalize方法是没有意义的。

对象将被添加到终结队列,并且只有在该对象没有任何活动引用时(在第一个GC周期中),才会调用Finalize方法。因此,你有责任取消注册必要的事件。否则,只要有对该对象的引用,Finalize就不会执行。

这里有一个关于取消注册事件处理程序的好参考:Is it necessary to explicitly remove event handlers in C#

0