2016-04-08 18 views
1

我運行一個測試函數來標識內存泄漏時:神祕內存泄漏覆蓋的靜態數據集

[TestMethod] 
public void DatabaseTools_Other_MemoryTest() 
{ 
    for (int i = 0; i < 100; i++) 
    { 
     try 
     { 
      var r = DatabaseTools.GetDataSet(true); 
      r = null; 
     } 
     catch (Exception e) 
     { 
      int EndPoint = i; 
     } 
    }   
} 

這種方法的目的是調用DatabaseTools.GetDataSet(真),直到遇到一個OutOfMemoryException,發生在第三次或第四次加載期間。不過,據我所知,這應該實際上不能happen-這是DatabaseTools.GetDataSet:

public static DataSet GetDataSet(bool setData, string sqlText = null, string strConnection = null) 
{ 
    sqlText = sqlText ?? FullFilemakerQuery; 

    if (setData) 
    { 
     Database = strConnection; 
     Data = new DataSet(); 
    } 

    DataSet dataSet = new DataSet(); 

    using (SqlConnection connection = GetConnectionString()) 
    { 
     using (SqlDataAdapter dataAdapter = new SqlDataAdapter(sqlText, connection)) 
     { 
      dataAdapter.SelectCommand.CommandType = System.Data.CommandType.Text; 
      if (setData) 
      { 
       dataAdapter.FillSchema(Data, SchemaType.Source); 
       DisableAutoIncrement(Data); 
       dataAdapter.Fill(Data); 
       NameTables(Data, sqlText); 

       BuildDataKeysAndRelations(Database); 
       dataSet = null; 
      } 
      else 
      { 
       dataAdapter.FillSchema(dataSet, SchemaType.Source); 
       DisableAutoIncrement(dataSet); 
       dataAdapter.Fill(dataSet); 
       NameTables(dataSet, sqlText); 
      } 
     } 
     connection.Close(); 
    } 
    return dataSet ?? Data; 
} 

public static void NameTables(DataSet dataSet, string sqlText) 
{ 
    for (int i = 0; i < dataSet.Tables.Count; i++) 
    { 
     dataSet.Tables[i].TableName = sqlText.Split(';')[i].Split(Dividers, StringSplitOptions.None)[1].Trim(); 
    } 
} 

public static void DisableAutoIncrement(DataSet data) 
{ 
    foreach (DataTable T in data.Tables) 
    { 
     T.PrimaryKey.Select(c => { c.AutoIncrement = false; return c; }).ToList(); 
    } 
} 

當只傳遞「真」這個功能,它集SQLTEXT等於靜態FullFileMakerQuery它選擇的一切程序可以從數據庫中使用,然後獲得默認的數據庫名稱(數據庫有一個自定義設置器,當給定一個空值或空值時,它將自己設置爲默認值),並將靜態數據設置爲新的數據集。我們已經嘗試在此處將其設置爲null(沒有更改),並且我們嘗試使用導致錯誤的Data.Dispose()。因爲這個函數也可以返回數據集,而不需要設置全局數據,所以我們初始化一個新的DataSet數據集。然後我們執行標準連接,數據適配器,fillchema,加載數據。

的古怪:通過在存儲器測試功能設置斷點和保存轉儲,加載數據集一次,將存儲器的某個量,重裝它使用更少存儲器(約36000字節System.Data.Common.StringStorage)然後再次重新加載使用更多內存(在與之前相同的地方大約120,000字節)。如果我們重新加載一次,它由於OutOfMemoryException而使用更多的內存和崩潰,此時我不知道是什麼導致了它。

+0

我懷疑'BuildDataKeysAndRelations'方法。你能展示那種方法的內容嗎? –

+1

你在這裏混雜着:獲取數據和保存數據。如果你想分開這兩個問題,你會有一個更清潔的程序(並且更容易看到錯誤)。 – nvoigt

+0

@ThariqNugrohotomo我也是這樣做的,但註釋掉這行對內存泄漏沒有影響。 –

回答

0

該函數可能會創建新的變量等,但不釋放內存,因爲垃圾回收器沒有時間去做。你可以試試GC.Collect()來強制它,看看它是否能解決你的問題。除非必要,否則不建議這樣做,因爲它可能會產生性能問題,因爲其餘應用程序必須等到GC完成。我的應用程序在低RAM服務器上遇到類似問題,並且強制清理幫助。

+0

我試着運行GC.Collect(),後面跟着GC.WaitForPendingFinalizers()以確保它完成,並且它沒有改變結果。 –

+0

不應該只是一個評論? –

+0

想要,還不能評論。抱歉。 – adsamcik

0

在您再次撥打new之前,您絕對不會在您的DataSet上撥打.Dispose(),既不是返回值,也不是您的靜態變量。

因爲您正在使用using塊已與其他類,我想你知道該怎麼做才能實際調用.Dispose()就可以了。

打開Visual Studio靜態代碼分析,它會給你警告,你應該忘記這樣做。

+0

實際上,我們已經試過但─改變代碼 如果(使用setData) { 如果(數據!= NULL){ Data.Dispose(); } Database = strConnection; Data = new DataSet(); } 並在dataSet = null之前添加dispose語句;沒有效果。 –