如何通过处理静态方法来防止故障(内存泄漏)?

时间:2012-02-24 05:53:25

标签: c# asp.net oop memory-leaks garbage-collection

我正在使用ASP.NET 4.0。

从过去几周开始,很少有用户抱怨应用程序开始出现故障。 GridView突然开始显示DropDown控件的内容,该控件是同一用户或另一个并发用户可能在当天的任何时间点访问过的。同样,DropDown控件可能会被任何旧结果集的RowID填充,而不是实际项目。

我遇到了一篇文章:Users seeing other users data in ASP.NET,其中作者讨论了导致内存泄漏行为的静态对象。

它提醒我项目中的一个类Static并包含public static方法。此类包含填充DropDown,返回查询输入的DataSet或基于查询输入返回标量对象的方法。

此课程的摘录如下:

public static class reuse
{
    public static void FillDropDownList(string Query, DropDownList DropDownName, string ConnectionStringParameter)
    {
        SqlDataReader dr;

        try
        {
            dbConnection.OpenConnection(ConnectionStringParameter);

            //Check whether the Drop Down has existing items. If YES, empty it.
            if (DropDownName.Items.Count > 0)
                DropDownName.Items.Clear();

            SqlCommand cmd = new SqlCommand(Query,dbConnection.cn);
            dr = cmd.ExecuteReader();

            DropDownName.Items.Add("-- Select --");
            DropDownName.Items.Add("All");
            while (dr.Read())
                DropDownName.Items.Add(dr[0].ToString());

            dr.Close();
        }
        catch (Exception ex)
        {
            rpkCustomErrorHandler.GetScript(HttpContext.Current.Response,ex.Message.ToString());
        }
        dbConnection.CloseConnection();
    }
}

我想知道这是否是我上面讨论的故障的原因。如果是,有没有办法在方法任务完成后处理静态方法。我是否需要将类从Static更改为默认的普通类?

被修改

我有另一个也是静态的类,由上面的类使用:

public static class dbConnection
{
    public static SqlConnection cn = new SqlConnection();

    public static void OpenConnection()
    {
        try
        {
            cn.ConnectionString = ConfigurationManager.ConnectionStrings["cnWebTwDrill"].ToString();

            if (cn.State == ConnectionState.Closed)
                cn.Open();
        }
        catch (Exception)
        {
            throw;              
        }
    }
}

我应该从Connection Class中删除“Static”并每次使用一个唯一的实例来调用此类吗?

3 个答案:

答案 0 :(得分:3)

您向我们展示的代码是静态类/方法使用不当的一个例子。你输入一个静态的方法或类,这些东西很容易适合一个对象并且不需要处理状态。

您在那里的功能应该分为业务层(将检索数据)和UI / COntroller(在本例中为Page),您将数据分配给服务器控件。所有这些操作都特定于请求,没有理由使用静态方法。只是(坏)程序编程的标志。在处理数据库访问(或一次性对象)时,您应该使用 using 语句。像这样的东西

using(var conex=GetConnection())
{
   try
   {
     conex.Open(); 
     //do stuff

    var cmd= new SqlCommand();//cfg command
    using (var rd= cmd.ExecuteReader())   
      {
           //do read
      }
   }
   catch(Exception ex)
    {
       //handle exception
    }
}

using 语句会在块结束时自动调用Dispose。它基本上是

的捷径
try {}
finally{ //dispose }.

答案 1 :(得分:1)

它不是泄漏或处理利用静态对象与状态的问题。此函数是静态的,但它不是有状态的,因此操作的所有上下文都存在于调用中,因此此类中不是参数的所有对象都将自动清除。但是,如果您定义了某种类型的静态数据,则同一应用程序域中的任何用户都将共享该值。话虽如此,你必须谨慎使用静态,因为它们难以测试替换,并且在多线程情况下非常困难。

答案 2 :(得分:1)

我怀疑您看到的错误是由于内存泄漏或无法处理静态对象造成的。

但是,回答你的问题:释放静态对象所占用的内存的唯一方法是将关联的静态引用设置为null。之后,它们将无法访问,GC将负责其余的工作。

可能有助于解决实际问题的两件事:

  1. 错误的缓存策略可能导致无意的数据共享(在HTTP级别或与ASP.NET对象缓存,输出缓存等)
  2. 请务必使用锁定所有对可在线程之间共享的静态对象的引用,其中一个线程可能会写入该对象而另一个线程正在读取该对象。
  3. BTW,OP中的静态方法似乎没有使用任何静态对象;它触及的一切似乎都是作为一个论点传递的。仅静态方法不会分配或保存内存引用。

    <强>更新

    尝试在页面请求之间共享单个数据库连接是一个错误,几乎肯定会导致未定义的行为(例如,一个页面可以发出查询,而另一个页面读取响应)。数据库连接已由运行时池化;您不需要自己优化该部分。每个页面请求不仅应该使用新的SqlConnection,还应该在连接对象上调用Dispose(),以便立即将其释放回池中。