类型'的例外情况;System.OutOfMemoryException';被扔了。C#使用IDataReader时
我有一个应用程序,其中我必须从数据库中获取大量数据。 因为它无法获取所有这些行(接近2000000行…),所以我将其分为几行,每次运行sql查询,每次只获取200000行 我使用DataTable输入所有数据(意味着所有2000000行都应该在那里) 头几次跑步很好。然后它会失败,并出现OutOfMemoryException 我的代码如下所示:类型'的例外情况;System.OutOfMemoryException';被扔了。C#使用IDataReader时,c#,sql,exception,datareader,using-statement,C#,Sql,Exception,Datareader,Using Statement,我有一个应用程序,其中我必须从数据库中获取大量数据。 因为它无法获取所有这些行(接近2000000行…),所以我将其分为几行,每次运行sql查询,每次只获取200000行 我使用DataTable输入所有数据(意味着所有2000000行都应该在那里) 头几次跑步很好。然后它会失败,并出现OutOfMemoryException 我的代码如下所示: private static void RunQueryAndAddToDT(string sql, string lastRowID, SqlCon
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);
}
}
在我看来,似乎读者一直在收集行,这就是为什么它只在第三轮或第二轮抛出异常
使用程序不应该在完成时清理内存吗?
什么可以解决我的问题
注意:我应该解释一下——我别无选择,只能将所有这些行都放到datatable中,因为我以后会对它们进行一些操作,而且行的顺序很重要,我不能拆分它,因为有时我必须将一些行的数据设置为一行,依此类推,所以我不能放弃
谢谢。我认为您的内存不足,因为您不断添加到数据表中的所有行的数据表都太大了 在这种情况下,您可能需要尝试不同的模式
您不需要将行缓冲在列表(或数据表)中,而只需在行到达时生成可用的行即可吗?您正在将数据副本存储到
dt
。您存储的内容太多,机器内存不足。因此,您几乎没有选择:
- 增加可用内存
- 减少正在检索的数据量
boot.ini
中启用3GB开关,则为3GB),因此,如果希望寻址更多内存,则可能需要切换到64位(计算机和进程)
检索更少的数据可能是一条出路。根据您试图实现的目标,您可能能够在数据的子集上执行任务(甚至可能在单个行上)。如果您正在执行某种聚合(例如,从数据生成摘要或报告),则可以使用。请检查您正在构建的是64位进程,而不是32位进程,这是Visual Studio的默认编译模式。为此,右键单击您的项目,属性->构建->平台目标:x64。与任何32位进程一样,以32位编译的Visual Studio应用程序的虚拟内存限制为2GB 64位进程没有这个限制,因为它们使用64位指针,所以它们的理论最大地址空间是16 EB(2^64)。实际上,Windows x64将进程的虚拟内存限制为8TB。然后,解决内存限制问题的方法是以64位编译 但是,默认情况下,VisualStudio中对象的大小仍然限制为2GB。您可以创建几个组合大小大于2GB的阵列,但默认情况下无法创建大于2GB的阵列。如果仍然希望创建大于2GB的阵列,可以通过向app.config文件中添加以下代码来实现:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
由于您使用的是数据表
,所以让我来分享一下我使用数据表时遇到的一个随机问题。检查生成属性。我遇到数据表随机抛出内存不足异常的问题。事实证明,该项目的构建平台目标设置为首选32位
。一旦我取消选择该选项,随机内存不足异常就消失了。只是一条注释,如果数据大小增加一倍或三倍,该怎么办。必须有一个方法来只提取一些数据,否则以后可能会遇到很多麻烦。加载200万行是非常罕见的-大多数时候,这种方法是为了最大限度地减少加载的数据量。如果需要2M行,DataTable可能不是最好的模型(DataTable有开销)。我个人会将其加载到POCO模型中。使用并不能真正清除内存,也不会触发收集。另外:一个读者只有一小部分buffer@MarcGravell:这一点很好,但它使读卡器使用的内存符合收集条件,在这种情况下,如果结果没有存储在其他位置,则会阻止OOM。不,因为读卡器没有保存所有数据:这是一个流式API。对我来说很有用!谢谢非常感谢。为meI工作我使用32位应用程序,我试图从sql reader将1700000条记录添加到数据表中,因为它抛出了内存不足异常。再次使用上述解决方案后,它抛出了相同的错误。请建议我解决他的问题。