2017-08-03 8 views
0

IISでホストされているasp.net Webサイトがあります。私は最近、大きな結果セットがデータベースから返され、IISワーカープロセスのメモリが増加し続けていることに気付きました(クエリが実行されるたびに約400MB)。これらの大規模なクエリのうちのいくつかが同時に実行された場合、メモリを食べるだけで(5GBに達したと見ています)、サーバーの速度が低下します。DataTableを使用したASP.NETメモリリーク/高メモリ

データがDataTableにロードされるときに、コードの1行に絞り込みました。

using (SqlConnection connection = new SqlConnection(connectionString)) 
using (SqlCommand command = new SqlCommand(storedProcedureName, connection)) 
using(DataTable dataTable = new DataTable()) 
{ 
    command.CommandType = System.Data.CommandType.StoredProcedure; 
    connection.Open(); 

    using (SqlDataReader reader = command.ExecuteReader()) 
    { 
     // Memory Spikes on dataTable.Load 
     dataTable.Load(reader); 
    } 
} 

私が理解していないことは、DataTableに割り当てられているメモリが予想通りに処理されていないようです。 DataTableが範囲外になったり、ユーザーがサイトから離れたり、ユーザーがサイトからログアウトした場合でも、メモリは同じレベルのままです。これは明らかにマルチユーザシステムの問題です。

私はメモリプロファイラーを使用していて、DataTableで保持されているクエリの結果である何千もの文字列をメモリに保持していますが、ここからどこに行くのかはわかりません。私はこれをどのように扱うべきなのか誤解していますか?

+1

https:// stackoverflow。com/questions/913228/should-i-dispose-dataset-and-datatable/1603516#1603516 – user6144226

+0

1回のクエリの後に400 MBのメモリがありますか? DBから取ったデータセットを最小化することを検討しましたか? – Piotr

+0

Piotr、残念ながら、すぐには可能ではありませんが、それはすべて同じ方法で設計された幅広いレポートを備えたやや古いシステムです。 – IanSoc

答えて

0

これは問題ではありません。ガベージコレクターの仕組みです。 オブジェクトを破棄すると、すぐにメモリから削除されません。これはガベージコレクタに処分する準備ができているとマークされているだけです。

この

スタックは自動的にメソッドの最後にクリアされているMS試験の本からの引用です。 CLRはこれを処理し、あなたはそれを心配する必要はありません。ヒープは別の話です。ガベージコレクタによって管理されています。ガベージコレクタのない管理されていない環境では、どのオブジェクトがヒープに割り当てられているかを追跡し、明示的に解放する必要があります。 .NET Frameworkでは、これはガベージコレクタによって行われます。

ガベージコレクタはマークとコンパクトアルゴリズムで動作します。コレクションのマークフェーズは、ヒープ上のどのアイテムがルートアイテムによって参照されているかをチェックします。ルートには、静的フィールド、メソッドパラメータ、ローカル変数、またはCPUレジスタを使用できます。ガベージコレクタがヒープ上に「生きている」アイテムを見つけた場合は、アイテムにマークを付けます。ヒープ全体をチェックした後、コンパクトな操作が開始されます。ガベージコレクタは、すべてのライブヒープオブジェクトをまとめて移動し、他のすべてのオブジェクトのメモリを解放します。これを行うために、ガベージコレクタは、すべてのマーキングと圧縮を実行している間に状態が変化していないことを確認する必要があります。このため、収集操作を実行している間は、すべてのスレッドがフリーズします。また、生きているオブジェクトへのすべての参照が正しいことを確認する必要があります。オブジェクトを移動した後、ガベージコレクタはオブジェクトへの既存の参照をすべて修正します。

あなたは使用してクリーニングを実行するためにガベージコレクタを強制しようとすることができます

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

また、GCは、複数の世代を使用し、唯一の世代0は、最初にそれをクリーンアップし、GC-アップをきれいに簡単です。 GCだけが十分なメモリを解放できないと判断したとき、それは他の世代を処理し始めるでしょう。そして、これらの世代に移動すると待ち時間が生じる可能性があります。

更新:大きなデータセットを小さなチャンクに分割し、それに応じて検索することもできます。

+0

こんにちはSouXin、あなたの答えをありがとう。ガベージコレクタを直接呼び出すとメモリがクリアされますが、なぜそれが自動的に収集されないのか不明です。私は何も心配しておらず、実際に必要なときに収集されますか?私がこれを心配しているのは、複数のレポートを持つマルチユーザーシステムでこれが起こっているためで、IISに割り当てられたメモリが5GBに達しているのがわかりました。私はこれについて心配してはいけませんか? – IanSoc

+0

データテーブルが第1世代または第2世代にあるとGCが判断した場合は、論理を変更してください。世代0の場合は心配しないでください。データテーブルのDisposeメソッドを上書きするだけで何ができるのですが、すぐに自動的にクリーンアップされることを確認できます。それは自動的に収集しますが、ある程度の時間が経過するとBTWはそれを収集します。 – SouXin

関連する問題