【问题标题】:Excessive Memory Spike On Postback Because Of Datatable由于数据表,回发时出现过多的内存峰值
【发布时间】:2014-12-23 13:12:53
【问题描述】:

我基本上有一个包含邮政编码区域的列表框,即:AE、CW、GU 等。

用户选择此选项,然后发生回发 - 构建 sql 语句并执行数据库查询操作,并将结果返回到名为 tempdata 的数据表。

到目前为止一切顺利。然后我需要遍历这个数据表并将记录复制到我的主视图状态数据表,这是谷歌地图 api 的数据源。

  DataTable tempstore = GetData(querystring, "");

                        //check tempstore has rows otherwise add defaultcust as default otherwise map will be blank

                        if (tempstore.Rows.Count == 0)
                        {
                            tempstore = GetData("WHERE CUSTCODE=='CD344'", "");

                            infoalert.Visible = true;

                            infoalert.InnerHtml = "No Results Returned For Selection";
                        }

                        foreach (DataRow row in tempstore.Rows)
                        {

                            dtpc.ImportRow(row);
                            dtpc.AcceptChanges();

                        }

        //database command
 using (OleDbConnection con = new OleDbConnection(conString))
            {
                using (OleDbCommand cmd = new OleDbCommand(query))
                {
                    using (OleDbDataAdapter sda = new OleDbDataAdapter())
                    {
                        cmd.Connection = con;

                        sda.SelectCommand = cmd;

                        sda.Fill(dt5);

                    }
                }
            }    

所以我的主要数据表可以随着用户添加更多邮政编码而不断增长。但是,当它达到大约 500 行左右时,我只会在回发时获得巨大的内存峰值,然后它会恢复下来。我的 ram 使用量从 2gb 变为 3gb,如果选择了更多的邮政编码,它会最大化内存并使我的电脑崩溃。

如果我删除:

dtpc.Importrow(row);

内存峰值完全消失,显然是因为主数据表没有行。我以为你只有在有数千行时才会遇到内存问题?

任何帮助将不胜感激。

谢谢你

【问题讨论】:

  • 虽然这可能无法解决您的内存泄漏问题,但如果将 dtpc.acceptchanges 放在循环之外,您可以获得性能提升。在导入所有行之后调用一次而不是在每一行之后调用一次更便宜。
  • 谢谢,这对内存问题没有帮助:(
  • 把你的代码格式化到左边

标签: c# .net memory-management memory-leaks datatable


【解决方案1】:

你真的需要一次所有的行吗
DataReader 将一次访问一行并将您的内存保持在最低限度
DataReader class

如果您一次需要所有数据,请为数据创建一个 strut 类,并将其保存在像 List 这样的集合中。 DataTable 是一个沉重的对象。

如果您通过任务管理器测量内存,请注意它不是很准确。

【讨论】:

  • 是的,我一次需要所有行,因为这些是用户选择。这些行被绘制在谷歌地图上,供用户直观地看到。我不明白 500 行左右如何会导致内存出现如此巨大的峰值?
  • 创建一个strut类来保存你的数据。 DatatTable 是一个沉重的集合。
  • 好的,所以目前我正在使用这个:tempstoredt > maindt > repeater>googlemaps。我将如何使用您的建议绑定到转发器数据源
  • 我不是要代码。一个简单而简短的解释将不胜感激。但是感谢您的建议 - 网上也有很多资料说数据表很好,除非您达到数千行。
【解决方案2】:

首先,确保您将所有 SQL 执行包装在适当的“使用”子句中。这很可能是您的问题的原因。

using (var command = new SqlCommand())
{
    // Some code here
}

就像 Blam 所说,DataTable 对于您的目的来说太重了。

您可以很容易地将数据行转换为类对象:

var datasourceList = new List<YourCustomObject>();

foreach (DataRow row in tempstore.Rows)
{
    var newMapsObject = new YourCustomObject
    {
        Value1 = row.Field<String>("Value1ColumnName"),
        Value2 = row.Field<String>("Value2ColumnName")
    };

    datasourceList.Add(newMapsObject);
}

viewStateList.AddRange(datasourceList);

要将自定义集合绑定到数据显示(例如中继器),请将列表分配给所述显示的 .DataSource 属性,然后调用 .DataBind()。这适用于大多数 ASP.NET 数据显示对象。

repeater1.DataSource = viewStateList;
repeater1.DataBind();

【讨论】:

  • 非常感谢您的回复。请参阅我的原始帖子,我已使用语句添加了数据库。我会尝试你的建议并转换为类对象。我是否能够像使用这样的数据表一样将其添加到视图状态: ViewState["dtpc"] = dtpc; Repeater1.DataSource = dtpc; Repeater1.DataBind();
  • 你应该可以,但我无法为你测试。请花时间正确对齐您发布的代码 - 值得多花几分钟使其更具可读性,而不是从 Visual Studio 复制+粘贴它。
  • 我已按照您的建议将其放入列表中,并将自定义对象添加到此列表中。内存峰值更好,即我可以在它开始变坏之前添加更多的邮政编码。但它仍然会在回传时达到峰值,达到 600mb 左右的峰值,然后又回落。它肯定不应该使用这么多内存吗?
猜你喜欢
  • 1970-01-01
  • 2013-10-20
  • 1970-01-01
  • 2020-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-01
相关资源
最近更新 更多