System.OutOfMemoryException'被扔出来.c#使用IDataReader时

本文关键字:使用 IDataReader OutOfMemoryException System | 更新日期: 2023-09-27 17:49:30

我有一个应用程序,我必须从数据库获得大量的数据。因为它没有得到所有这些行(它接近2,000,000行…),我把它分成几行,每次运行sql查询,每次只得到200,000行。

我使用DataTable,我输入所有的数据(意思是-所有的2,000,000行应该在那里)。

前几次运行很好。然后它以OutOfMemoryException失败。

我的代码工作如下:

private static void RunQueryAndAddToDT(string sql, string lastRowID, SqlConnection conn, DataTable dt, int prevRowCount)
    {
        if (string.IsNullOrEmpty(sql))
        {
            sql = generateSqlQuery(lastRowID);
        }
        if (conn.State == ConnectionState.Closed)
        {
            conn.Open();
        }
        using (IDbCommand cmd2 = conn.CreateCommand())
        {
            cmd2.CommandType = CommandType.Text;
            cmd2.CommandText = sql;
            cmd2.CommandTimeout = 0;
            using (IDataReader reader = cmd2.ExecuteReader())
            {
                while (reader.Read())
                {
                    DataRow row = dt.NewRow();
                    row["RowID"] = reader["RowID"].ToString();
                    row["MyCol"] = reader["MyCol"].ToString();
                    ... //In one of these rows it returns the exception.
                    dt.Rows.Add(row);
                }
            }
        }
        if (conn != null)
        {
            conn.Close();
        }
        if (dt.Rows.Count > prevRowCount)
        {
            lastRowID = dt.Rows[dt.Rows.Count - 1]["RowID"].ToString();
            sql = string.Empty;
            RunQueryAndAddToDT(sql, lastRowID, conn, dt, dt.Rows.Count);
        }
    }

在我看来,好像阅读器一直在收集行,这就是为什么它只在第三轮或第二轮抛出异常。

Using不应该清理内存吗?什么可以解决我的问题?

注意:我应该解释一下——我别无选择,只能把所有这些行都放到数据表中,因为我以后会对它们进行一些操作,而且行的顺序很重要,我不能分割它,因为有时我必须把一些行的数据设置成一行,等等,所以我不能放弃。

谢谢。

System.OutOfMemoryException'被扔出来.c#使用IDataReader时

检查您正在构建64位进程,而不是32位进程,这是Visual Studio的默认编译模式。为此,右键单击项目,Properties -> Build -> platform target: x64。与任何32位进程一样,用32位编译的Visual Studio应用程序的虚拟内存限制为2GB。

64位进程没有这个限制,因为它们使用64位指针,所以它们的理论最大地址空间是16艾字节(2^64)。实际上,Windows x64将进程的虚拟内存限制为8TB。解决内存限制问题的方法是用64位编译。

然而,在Visual Studio中对象的大小仍然被限制在2GB,默认情况下。您将能够创建多个数组,它们的总大小将大于2GB,但默认情况下不能创建大于2GB的数组。如果您仍然希望创建大于2GB的数组,则可以通过在app.config文件中添加以下代码来实现:

<configuration>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" />
  </runtime>
</configuration>

我认为你只是用完内存,因为你的数据表从你不断添加的所有行变得如此之大。

在这种情况下,您可能需要尝试不同的模式。

与其在列表(或DataTable)中缓冲行,不如在行到达时简单地生成可用的行?

既然你使用的是DataTable,让我分享一个随机的问题,我使用一个。检查Build属性。我有一个问题,数据表抛出内存异常随机。结果是,项目的构建平台目标被设置为Prefer 32-bit。一旦我取消选择该选项,随机内存不足异常就消失了。

您正在将数据的副本存储到dt。您只是存储了太多,以至于机器的内存即将耗尽。所以你有几个选择:

  • 增加可用内存
  • 减少您正在检索的数据量。

要增加可用内存,可以向机器添加物理内存。请注意,32位机器上的。net进程将无法访问超过2GB的内存(如果您在boot.ini中启用3GB开关则为3GB),因此如果您希望寻址更多的内存,可能需要切换到64位(机器和进程)。

检索更少的数据可能是可行的方法。根据您想要实现的目标,您可能能够在数据的子集上执行任务(甚至可能在单独的行上)。如果您正在执行某种聚合(例如,从数据生成摘要或报告),则可以使用Map-Reduce。