2016-06-24 17 views
2

IBM.Data.DB2.DB2DataAdapterオブジェクトを使用して、異なるサーバー上の異なるデータベースに複数の接続を作成しています。私は別のサーバー上に約20かそこらのデータベースを持っている場合、私は最終的にこの例外を取得して終了その後DB2Connectionオブジェクトループオープンおよびクローズメモリー例外

foreach (MyDBObject db in allDBs) 
{ 
    //Database Call here for current DB...//Get SQL, then pass it to DB call 
    QueryCurrentDB(command); 
} 

...

DB2Connection _connection;  

Public DataTable QueryCurrentDB(DB2Command command) 
{ 

    _connection = new DB2Connection(); 
    DB2DataAdapter adapter = new DB2DataAdapter(); 

    _connection.ConnectionString = string.Format("Server={0};Database={1};UID={2};PWD={3};", _currentDB.DBServer, _currentDB.DBName, _currentDB.UserCode, _currentDB.Password); 
    command.CommandTimeout = 20; 
    command.Connection = _connection; 
    adapter.SelectCommand = command;     
    _connection.Open(); 

    adapter.Fill(dataTable); 

    _connection.Close(); 
    _connection.Dispose(); 

    return dataTable; 
} 


私の基本的なループとの接続構造は次のようになります。私は各dbインスタンスのメモリ割り当てを制御することはできません。

ERROR [57019] [IBM] SQL1084Cデータベース・マネージャーは、オペレーティング・システム・カーネルのメモリー限界に達したため、共用メモリーの割り振りに失敗しました。私はこの問題を回避することができましたSQLSTATE = 57019

唯一の方法は、次のような、各DBの呼び出しの前にスレッドの睡眠を置くことです:

System.Threading.Thread.Sleep(3000); 

私は何か提案をいただければ幸い、これを憎みます。

+0

コードは明確な画像を与えません( 'sqlCommand'はisntが使用され、how/whereは' _connection'が作成されていません)。しかし、エラーメッセージは具体的に 'DBConnection'を意味しません。 DBProviderオブジェクトは破棄する必要があり、あなたのように見えません。 – Plutonix

+0

私はDB2オブジェクトをどのように使用しているかをより良く示すためにコードを更新しました。 – Airborne

答えて

3

Connection,CommandおよびDataAdapterはすべてIDisposableであり、割り当てられたリソースを解放する必要があることを示しています。しかし、実際にはDBConnectionオブジェクトのみが処理されます。特にあなたのようなループでは、漏れを防ぐためにそれらを処分することが重要です。

私はDB2プロバイダを持っていませんが、これらはすべて、特にこの点ではほとんど同じです。 MyDBObjectで始まるコードのリファクタリングから始めます。むしろちょうどそれがあなたのための接続(複数可)を作成する必要があり、接続文字列のparamsを握っより:

class MyDBObject 
{ 
    private const string fmt = "Server={0};Database={1};UID={2};PWD={3};"; 
    ... 
    public DB2Connection GetConnection() 
    { 
     return new DB2Connection(string.Format(fmt, 
        DBServer,DBName,UserCode,Password)); 
    } 
} 

次にループ方式:最も重要な

// this also could be a method in MyDbObject 
public DataTable QueryCurrentDB(string SQL) 
{ 
    DataTable dt = new DataTable(); 
    using (DB2Connection dbcon = currentDB.GetConnection()) 
    using (DB2Command cmd = new DB2Command(SQL, dbcon)) 
    { 
     cmd.CommandTimeout = 20; 
     dbcon.Open(); 
     dt.Load(cmd.ExecuteReader()); 
    } 
    return dt; 
} 
  • は、IDisposableオブジェクトであることに注意してくださいすべてusingブロックで囲まれています。これにより、ターゲットを破棄(およびクローズ)し、割り当てられたすべてのリソースを解放します。
  • テーブルを埋めるのにDataAdapterは必要ありません。これを省略すると、IDisposableというものが1つ少なくなります。
  • コマンドを渡すのではなく、SQLを渡します。これにより、DBCommandオブジェクトを作成、使用、廃棄することもできます。
  • 同じDBに2つのテーブルがポーリングされる可能性がある場合は、同じ接続で両方のテーブルを満たすことができるようにさらにリファクタリングします。

前:3つのオブジェクトのうち2が配置されていませんでした(反復ごと!)
後:2つのオブジェクトのうち2が配置されています。

私は原因がDBCommandオブジェクト(this questionに似ています)であったと考えますが、それらを組み合わせることもできます。

スレッドをスリープ状態にする(おそらく)のは、GCがクリーンアップに追いつく機会を与えるためです。あなたはおそらくまだ森の外に出ていないでしょう。上記のリンクは、400回の反復で問題にぶつかっていました。 20または40(20 * 2オブジェクト)は、リソースを使い果たすための非常に少数のようです。

私は、コードの他の部分も適切に処理していないと考えています。そのループは、ラクダの背中を壊すストローです。使用されている他のループやDBオブジェクトを探し、それらを破棄してください。基本的には、Dispose()メソッドを持つものはusingブロックで使用する必要があります。

+0

私は自分のコードを変更し、今日のあなたの提案をテストします。どうしたらいいのか教えてくれます。 – Airborne

+0

私は、ステートメントを使用して、20以上の異なるdb接続とクエリを使用してdbオブジェクトをラップしました。ありがとう! – Airborne

+0

よろしくお願いします。問題のコードが実際に問題を明らかにしたことに留意してください。私はそのアプリがそれらの20〜40個のオブジェクトを傾ける余裕があると思うので、他の場所のコードも漏れそうです。実際のキーは答えの最後の文です:* "Dispose()メソッドを持つものは、usingブロックで使用すべきです" * – Plutonix

関連する問題