【问题标题】:Running out of memory when processing 4 million records处理 400 万条记录时内存不足
【发布时间】:2015-06-05 09:20:12
【问题描述】:

我有以下代码尝试处理 4,000,000 条数据库记录:

private void intenseProcess4()
{
    using (connection1 = new SqlConnection("connection string goes here"))
    {
        using (command1 = new SqlCommand(@"stored procedure name goes here", connection1))
        {
            command1.CommandType = CommandType.StoredProcedure;

            try
            {
                connection1.Open();

                using (reader1 = command1.ExecuteReader())
                {
                    while (reader1.Read())
                    {
                        int PrjNameIndex1 = reader1.GetOrdinal("full_path");
                        Directory.CreateDirectory(Path.Combine(reader1.GetString(PrjNameIndex1)));
                    }

                    if (reader1.NextResult())
                    {
                        while (reader1.Read())
                        {
                            System.IO.File.Copy(reader1.GetString(SourceIndex), reader1.GetString(DestinationIndex), true);
                        }
                    }
                }
            }
            catch (SqlException ex)
            {
                File.AppendAllText(Path.Combine(@"h:\X\log\error.log"), ex + " SqlException caught." + Environment.NewLine);
            }
        }
    }
}

一旦启动,它可以正常工作大约一个小时,但随后会出现以下错误消息:

Problem signature:
    Problem Event Name: CLR20r3
    Problem Signature 01:   devenv.exe
    Problem Signature 02:   12.0.21005.1
    Problem Signature 03:   524fcb34
    Problem Signature 04:   mscorlib
    Problem Signature 05:   4.0.30319.34209
    Problem Signature 06:   534894cc
Problem Signature 07:   226e
Problem Signature 08:   6
Problem Signature 09:   System.OutOfMemoryException
OS Version: 6.1.7601.2.1.0.256.49
Locale ID:  2057
Additional Information 1:   0a9e
Additional Information 2:   0a9e372d3b4ad19135b953a78882e789
Additional Information 3:   0a9e
Additional Information 4:   0a9e372d3b4ad19135b953a78882e789

当时,它只通过了大约 35,000 条记录

【问题讨论】:

  • 请注意,String DestinationString =String SourceString = 行是无用的。不过这应该不是问题。
  • 看起来你是从 VS 内部运行的。确保您使用的是 Release 版本,最好是在 VS 之外。
  • @xanatos,抱歉,正在使用 console.log 中的内容查看发生了什么。将该行删除为简单的问题,但我想它只是增加了混乱......
  • @HenkHolterman,我现在就试试。如果它再次出现错误,我想我会在大约一个小时后回来,因为这大约是得到上述错误所需的时间。
  • 我完全同意 Holterman 的分析。如果它仍然不起作用(但这会很奇怪,因为您没有分配太多 GC 内存),您可以尝试每 1000 个文件执行一次GC.Collect()。在while之前:int num = 0;里面whileif (++num % 1000 == 0) { GC.Collect(); }

标签: c# .net ado.net .net-3.5 sqldatareader


【解决方案1】:

试试CommandBehavior.SequentialAccess:

当您指定 SequentialAccess 时,您需要按照列的返回顺序读取它们,尽管您不需要读取每一列。一旦您读取了返回的数据流中的某个位置,就无法再从 DataReader 读取该位置处或之前的数据。

但是尝试一次性处理 4M 记录是否明智值得怀疑。我很确定您将永远成功复制 4M 文件并且保持结果集打开。你注定要一遍又一遍地重试。考虑改为使用批处理,检索一小组文件进行处理、复制、写下进度,然后再获取另一个批处理。如果发生崩溃,从上一个进度恢复。

您还应该考虑并行执行多个副本(使用异步 IO,而不是线程!)。

【讨论】:

  • 我不太确定最后一点,File.Copy 很容易使单个驱动器饱和。
  • 第二个想法也不太确定第一个。文件内容不在 Db 中,只是文件名。
  • 阅读器流式传输数据。一次使用的内存不应超过 1 行。我不明白为什么任意多的记录本身就是一个问题。
【解决方案2】:

使用终端命令而不是 GUI 创建存档。

【讨论】:

    猜你喜欢
    • 2017-01-27
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    • 2022-06-13
    • 1970-01-01
    • 2020-01-24
    • 2011-03-10
    • 1970-01-01
    相关资源
    最近更新 更多