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不应该清理内存吗?什么可以解决我的问题?
注意:我应该解释一下——我别无选择,只能把所有这些行都放到数据表中,因为我以后会对它们进行一些操作,而且行的顺序很重要,我不能分割它,因为有时我必须把一些行的数据设置成一行,等等,所以我不能放弃。
谢谢。
检查您正在构建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。