覆盖静态数据集时神秘内存泄漏

时间:2016-04-08 16:25:18

标签: c# memory-leaks

我正在运行测试功能来识别内存泄漏:

[TestMethod]
public void DatabaseTools_Other_MemoryTest()
{
    for (int i = 0; i < 100; i++)
    {
        try
        {
            var r = DatabaseTools.GetDataSet(true);
            r = null;
        }
        catch (Exception e)
        {
            int EndPoint = i;
        }
    }        
}

此方法的目标是调用DatabaseTools.GetDataSet(true),直到它遇到在第3次或第4次加载期间发生的OutOfMemoryException。但是,据我所知,这实际上不应该发生 - 这是DatabaseTools.GetDataSet:

public static DataSet GetDataSet(bool setData, string sqlText = null, string strConnection = null)
{
    sqlText = sqlText ?? FullFilemakerQuery;

    if (setData)
    {
        Database = strConnection;
        Data = new DataSet();
    }

    DataSet dataSet = new DataSet();

    using (SqlConnection connection = GetConnectionString())
    {
        using (SqlDataAdapter dataAdapter = new SqlDataAdapter(sqlText, connection))
        {
            dataAdapter.SelectCommand.CommandType = System.Data.CommandType.Text;
            if (setData)
            {
                dataAdapter.FillSchema(Data, SchemaType.Source);
                DisableAutoIncrement(Data);
                dataAdapter.Fill(Data);
                NameTables(Data, sqlText);

                BuildDataKeysAndRelations(Database);
                dataSet = null;
            }
            else
            {
                dataAdapter.FillSchema(dataSet, SchemaType.Source);
                DisableAutoIncrement(dataSet);
                dataAdapter.Fill(dataSet);
                NameTables(dataSet, sqlText);
            }
        }
        connection.Close();
    }
    return dataSet ?? Data;
}

public static void NameTables(DataSet dataSet, string sqlText)
{
    for (int i = 0; i < dataSet.Tables.Count; i++)
    {
        dataSet.Tables[i].TableName = sqlText.Split(';')[i].Split(Dividers, StringSplitOptions.None)[1].Trim();
    }
}

public static void DisableAutoIncrement(DataSet data)
{
    foreach (DataTable T in data.Tables)
    {
        T.PrimaryKey.Select(c => { c.AutoIncrement = false; return c; }).ToList();
    }
}

当只通过&#39; true&#39;对于这个函数,它将sqlText设置为等于静态FullFileMakerQuery,它选择程序可以从数据库中使用的所有内容,然后获取默认数据库名称(Database有一个自定义setter,当给定null或空值时,它将自己设置为默认),并将静态数据设置为新的DataSet。我们已经尝试在此时将其设置为null(无更改),并且我们尝试使用导致错误的Data.Dispose()。因为此函数也可以在不设置全局数据的情况下返回数据集,所以我们初始化一个新的DataSet数据集。然后我们做标准连接,数据适配器,fillschema,加载数据。

奇怪:通过在内存测试函数中设置断点并保存转储,加载数据集一次需要一些内存,重新加载它使用 less 内存(在System.Data中大约36,000字节。 Common.StringStorage)然后重新加载它再使用 more 内存(在与之前相同的地方大约120,000个字节)。如果我们再次重新加载它,它会因为OutOfMemoryException而使用更多的内存和崩溃,此时我不知道是什么原因造成的。

1 个答案:

答案 0 :(得分:0)

在再次致电.Dispose()之前,您永远不会在DataSet上致电new,也不会在返回值和静态变量上致电using

由于您已经在其他课程中使用.Dispose()块,我想您知道如何在其上实际调用$fileDir = '/home2/divine/Symfony/src/App/Bundle/Resources/public/files'; $form['my_file']->getData()->move($fileDir, 'book.pdf');

启用Visual Studio静态代码分析,如果您忘记这样做,它会向您发出警告。