重构 - System.OutOfMemoryException

时间:2010-06-22 21:16:45

标签: c# out-of-memory

我在尝试生成一些HTML报告时遇到'System.OutOfMemoryException'。

如何重新考虑这一因素,以便将其缓冲到文件中,而不是将其全部读取到内存中,然后写入文件。

数据表中有超过2000条记录,并且已经耗尽了2000行的内存。

DetailsUpdateTemplate包含一个多行的html片段。我假设我正在创建一个很大的字符串。

我正在使用C#,.NET 3.5

    internal static String SaveARSUpdateHTML(DataTable table, string fileName)
    {
        int recordCount = table.Rows.Count;

        Dictionary<String, object> templateCols = new Dictionary<string, object>();

        templateCols["Track"] = table.TableName;
        templateCols["ProdDate"] = DateTime.Now.ToShortDateString();
        templateCols["ProdTime"] = DateTime.Now.ToShortTimeString();
        templateCols["TotalRecords"] = recordCount;

        String detailOutput = String.Empty;
        for (int i = 0; i < table.Rows.Count; i++)
        {
            int ResultID = i + 1;
            DataRow row = table.Rows[i];
            String ReportDetails = DetailsUpdateTemplate;
            ReportDetails = ReportDetails.Replace(String.Format("{{{0}}}", "ResultID"), ResultID.ToString());
            foreach (DataColumn column in table.Columns)
            {
                String value = row[column.ColumnName].ToString();
                if (column.ColumnName.Equals("TF"))
                {
                    String display = value.Equals("no", StringComparison.CurrentCultureIgnoreCase) ? "none" : "block";
                    ReportDetails = ReportDetails.Replace(String.Format("{{{0}}}", "SuppressNewAddr"), display);
                }

                ReportDetails = ReportDetails.Replace(String.Format("{{{0}}}", column.ColumnName), value);
            } 

            detailOutput += ReportDetails;
        }

        templateCols["ReportDetails"] = detailOutput;

        String masterOut = MasterUpdateTemplate;
        foreach (KeyValuePair<string, object> pair in templateCols)
        {

            masterOut = masterOut.Replace(String.Format("{{{0}}}", pair.Key), pair.Value.ToString());
        }

        String outputFile = String.Format("{0}.htm", fileName);
        using (StreamWriter sw = new StreamWriter(outputFile))
        {
            sw.Write(masterOut);
        }

        return outputFile;
    }

3 个答案:

答案 0 :(得分:8)

在多次连接字符串时使用StringBuilders。

特别是在这里:

detailOutput += ReportDetails;

还使用DataReader。 DataReader将返回支持IDataRecord的记录,IDataRecord具有与DataRow类似的接口。

当我在ASP.NET中使用DataTables和DataSets时,你在OOM上遇到的行数大致相同,其中工作进程的内存有限,然后才会因为过多的内存使用而获得回收。这就是为什么我一直在积极地切换到DataReader。

<强>更新

DataReader解决方案看起来像......(TableReaders存在,但它不会在内存保护方面为你买任何东西,你只是得到一个类似于DataReaders的接口)

internal static String SaveARSUpdateHTML(DbDataReader myReader, string fileName)
    {

if (myReader.HasRows)
  while (myReader.Read())
  { 
      object something = myReader["TF"];
  }

else
  Console.WriteLine("No rows returned.");

myReader.Close();

答案 1 :(得分:3)

使用StringBuilder而不是string

答案 2 :(得分:1)

除了明显的StringBuilder

为什么不将它直接传输到文件,一次只处理一行,然后每行替换一次模板。这样你甚至不需要将整个报告保存在内存中。

巨大模板上的替换代码将是内存耗尽。