【问题标题】:How to reduce and how to clear the memory leak?如何减少以及如何清除内存泄漏?
【发布时间】:2012-12-27 13:31:08
【问题描述】:

我正在从数据库中读取我的 Datagridview 大约 25000 条记录。 在此阅读过程中,应用程序处于“无响应”模式,我可以看到它的进程内存越来越大,并停止在 2500-3800 MB 左右。 在我关闭包含Datagridview 的表单后,内存仍然是这个大小。

我的问题是:

  1. 读取海量数据时如何避免“无响应”?
  2. 当我从数据库中读取数据时,如何减少使用的内存量(我认为我做错了什么,因为它是很多内存)
  3. 关闭表单后如何清除所有内存?我正在处理所有我能处理的事情,但似乎 GC 仍然没有释放内存。我读到了一些关于未处理的事件处理程序的内容?

从DB读取到Datagridview的代码:

delegate void SetSearchCallback();
public void Search()
{
    sqlCommand="";
    if (this._dbReports.InvokeRequired)
    {
        SetSearchCallback d = new SetSearchCallback(Search);
        this.Invoke(d, new object[] { });
    }
    else
    {
            DateTime startDate = new DateTime(dateTimePicker1.Value.Year, dateTimePicker1.Value.Month, dateTimePicker1.Value.Day);
            DateTime endDate = new DateTime(dateTimePicker2.Value.Year, dateTimePicker2.Value.Month, dateTimePicker2.Value.Day);
            sqlCommand = "select * FROM cstPackages where _dateTime >= '" + String.Format("{0:yyyy-MM-dd}", startDate) + "' and _dateTime <='" + String.Format("{0:yyyy-MM-dd} 23:59:59.999", endDate) + "' order by _dateTime desc"; //reading the db from end to start   
    }

        if (sqlCommand != "")
        {
            using (SqlConnection sCon2 = new SqlConnection("Data Source=" + SettingsForm.getAddress + ";Initial Catalog=" + SettingsForm.getDatabase + ";Integrated Security=False;User Id=" + SettingsForm.getUser + ";Password=" + SettingsForm.getPassword + ";Connect Timeout=5;"))
            {
                try
                {
                    sCon2.Open();
                    using (da = new SqlDataAdapter(sqlCommand, sCon2))
                    {
                        dsReport.Clear();
                        da.Fill(dsReport, "cstPackages");
                        dbBind = new BindingSource(dsReport, "cstPackages");
                        if (firstTime == 0)
                            _dbReports.Columns.Clear();

                        _dbReports.DataSource = dbBind;

                        if (firstTime == 0)
                        {
                            updateDataGridSettings();
                            firstTime = 1;
                        }

                        _dbReports.Refresh();
                        sCon2.Close();
                        sCon2.Dispose();
                    }
                }
                catch (Exception c)
                {
                    fn.errorHandler(c.Message, SettingsForm);
                }
            }
        }
    }
}

当我关闭表单时:(btnPress=1 仅当我在 Datagridview 中填写了一些内容时)

private void Reports_FormClosing(object sender, FormClosingEventArgs e)
{
    _dbReports.Dispose();
    if (btnPress == 1)
    {
        dsReport.Dispose();
        da.Dispose();
        dbBind.Dispose();
    }
}

在表单关闭后的父表单中,我打电话给ReportForm.Dispose();

我知道Dispose 不会清除内存,但它应该可以帮助 GC 完成它的工作,对吧?

昨晚我让应用程序打开了一夜(在我关闭ReportForm之后),早上的内存是一样的(GC没有工作)

提前致谢。

编辑: 当我遇到 3GB 内存泄漏时,我的数据库中有大约 500 万条记录(我没有注意到,因为我有一个脚本正在填充我的数据库,我忘了停止它)

现在内存泄漏更容易接受,它比我将记录添加到 DataGridView 之前增加了大约 10 MB。 仍然.. 即使我使用虚拟模式并尝试关闭/处置所有可能的东西,每次填充内存都会增长约 10 MB。

【问题讨论】:

  • 您在 TaskManager 中看到的内容与 GC 没有直接关系(是否完成其工作)。除了在 GUI 中加载 25k 记录是不明智的之外,这里没有直接的问题迹象。
  • 25K 是可能的最大数量,应该在 2K 左右,但我想将应用程序发挥到极限并寻找错误。那么为什么当我用Datagridview关闭winform时,电脑没有清空内存呢?
  • 您需要同时显示所有这些行吗?您的 DataGridView 是否处于虚拟模式?你的记忆问题是什么时候出现的?当您从数据库加载或设置 DataGridView 的 DataSource 时?
  • 1.使用线程读取数据。 2.不要读那么多数据。 3. 让 GC 完成它的工作。
  • 我真的不需要一次显示所有行。我也许可以同时显示 1000 个。但是..我应该能够一次将它们全部导出到一个 CSV 文件中(但我可以在没有 datagridview 的情况下做到这一点,所以这不是问题)它不在Virtual Mode 中。应该是吗?当我调用这个函数search() 然后应用程序是Not Responding 并且从现在开始,任务管理器中的内存大小 i 越来越大,当它完成时应用程序“恢复生机”时发生错误"。

标签: c# winforms memory-leaks datagridview dataset


【解决方案1】:

1) 读取海量数据时如何避免“无响应”?

通过在单独的线程上执行这项昂贵的任务。在 WinForms 中,BackgroundWorker 非常有用,因为它会在作业完成后自动编组对主 UI 线程的调用。

2) 如何减少读取时使用的内存量 数据库(我认为我做错了什么,因为它是 很多内存)

您可以尝试启用Virtual Mode 并开始对数据进行分页。一次加载 25000 条记录是没有用的。无论如何,用户永远无法同时使用它们。

3) 关闭表单后如何清除所有内存?我正在处理 尽我所能,但似乎 GC 仍然没有释放 内存..我读了一些关于事件处理程序的内容 处置?

垃圾收集器会在您关闭表单后处理所有资源。只要确保您从不存储对它的任何引用,以便它符合 GC 的条件。

【讨论】:

  • 谢谢。我现在会检查它。我关闭并处理了所有可能的东西,但是关闭表单后内存仍然很大。有没有办法强制关闭所有引用?
  • 是的,有,确保没有任何引用指向此表单了。您也可以尝试调用GC.Collect() 来立即运行垃圾收集器。但请注意,这通常是不好的做法,因为 GC 更清楚何时最适合运行,而不会在应用程序中产生任何争用。
【解决方案2】:

我不小心实例化了一个表单而没有打开它……也没有处理它。它引起了非常相似的症状。他们所说的确实是真的:不要自己调用垃圾收集器。你还有其他问题。你需要处理你创造的东西。我不得不通过我的代码并找到其他几个类似的问题。多么阴险的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2014-04-19
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多