2016-04-08 9 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; 
     } 
    }   
} 

この方法の目標は、それがOutOfMemoryException例外に当たるまで(真)DatabaseTools.GetDataSetを呼び出すことです3回目または4回目のロード中に発生します。この関数にのみ「真」渡すとき

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(); 
    } 
} 

、それはすべてのものを選択し、静的FullFileMakerQueryにSQLTEXT等しい設定します。しかし、私はそれを理解するように、これは実際に今までにこれがDatabaseTools.GetDataSetあるhappen-べきではありませんプログラムはデータベースから使用することができ、デフォルトのデータベース名を取得します(データベースにはnullまたは空の値が指定された場合、デフォルトに設定されるカスタムセッターがあります)、静的データを新しいDataSetに設定します。この時点でnullに設定しようとしましたが(変更なし)、エラーを引き起こしたData.Dispose()を使用しようとしました。この関数はグローバルデータも設定せずにデータセットを返すだけなので、新しいDataSetデータセットを初期化します。次に、標準のconnect、data adapter、fillschema、load dataを実行します。

おかしな:メモリテスト機能にブレークポイントを設定し、ダンプを保存、データセットをロードすることによって、一度(System.Data.Common.StringStorageに約36,000バイト)は、少ないメモリを使用して再ロード、メモリの一部を要します再読み込みを行うには、をもう一度メモリ(前と同じ場所で約120,000バイト)使用します。もう一度リロードすると、OutOfMemoryExceptionのためにさらに多くのメモリとクラッシュが使用されます。この時点で何が原因か分かりません。

+0

私は 'BuildDataKeysAndRelations'メソッドを疑っています。そのメソッドの内容を表示できますか? –

+1

ここには、データの取得とデータの保持というものが混在しています。これらの2つの懸念を分けておけば、もっとクリーンなプログラム(そして間違いを見やすくする方法)が得られます。 – nvoigt

+0

@ ThariqNugrohotomo私もやったが、その行がメモリリークに影響を与えないとコメントしています。 –

答えて

0

この関数はおそらく新しい変数などを作成していますが、ガベージコレクタには時間がないためメモリを解放していない可能性があります。 GC.Collect()を強制して問題が解決するかどうか試してみてください。アプリケーションの残りの部分はGCが終了するまで待たなければならないため、パフォーマンスの問題を引き起こす可能性があるため、必要な場合を除き、これを行うことはお勧めしません。私は私のアプリで低RAMサーバー上の類似の問題を持っていたし、クリーンアップを助けた。

+0

GC.Collect()の後にGC.WaitForPendingFinalizers()を実行して、処理が完了し、結果が変更されていないことを確認しました。 –

+0

これはコメントではないでしょうか? –

+0

に募集しました、まだコメントできません。ごめんなさい。 – adsamcik

0

DataSet.Dispose()を電話することはありません。newを再度呼び出す前に、戻り値も静的変数も返さないでください。

usingブロックを他のクラスと併用しているので、実際に.Dispose()を呼び出すにはどうすればよいかわかります。

Visual Studioの静的コード解析を有効にすると、忘れた場合は警告が表示されます。

+0

私たちが実際に にコードを変更that-しようとした場合(のsetData) { 場合(データ= nullを!) { Data.Dispose(); } データベース= strConnection; データ=新しいDataSet(); } dataSet = nullの前にdisposeステートメントを追加します。効果はありません。 –

関連する問題