2010-06-22 50 views
1

嘗試生成某些HTML報告時,出現'System.OutOfMemoryException'。重構 - 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; 
    } 
+1

您沒有提供代碼的相關部分。所有這些代碼正在做的是修改內存中已經有**的一些數據以將其保存到文件中。 'DataTable'是內存中的。所以,而不是使用'DataTable'使用SqlDataReader並直接流到文件。 – 2010-06-22 21:21:27

+0

我正在從一個不同的庫中傳遞一個DataTable。我無法改變輸入行爲。 – 2010-06-22 21:28:00

回答

8

使用StringBuilders。

特別是在這裏:

detailOutput += ReportDetails; 

而且使用DataReader。 DataReader將返回支持IDataRecord的記錄,該記錄具有與DataRow類似的接口。

當我在ASP.NET中使用DataTables和DataSet時,您正在打擊OOM的行數大致相同,在ASP.NET中使用DataTables和DataSets時,工作進程在回收內存使用過多之前內存有限。這就是爲什麼我一直在盡我所能積極地切換到DataReader。

更新:

DataReader的解決方案會是什麼樣子......(TableReaders存在,但不會買你的東西在內存保護方面,你只希望得到更多的類似的DataReader接口)

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(); 
+0

Matthew,我懷疑是一個錯字:「當我使用DataTables和DataReaders」應該是「...和DataAdapters」? – 2010-06-22 21:27:33

+0

@亨克霍爾特曼。是的。數據前綴過多。 – MatthewMartin 2010-06-22 21:51:16

+0

StringBuilder可以/應該在這裏使用,不僅用於連接,還用於主循環中的Replace()。雖然閱讀器/適配器與該特定代碼無關。 – 2010-06-22 22:03:11

3

使用StringBuilder而不是字符串

1

除了明顯的StringBuilder

爲什麼不直接將此流式傳輸到文件,只是每次處理一行,然後每行進行一次模板替換。這樣你甚至不需要在整個內存中保存整個報告。

巨大模板上的替換代碼將成爲內存管理員。

相關問題