私は、いくつかの重い処理を行い、多くのメモリを使用し、さらにそれを行う .net 2.0 アプリを持っています。Web サービスからタスクを受け取り、その仕事を行い、結果を返し、それを無限に繰り返します。
主なコード構造は、これによって簡略化して説明できます
while (true)
{
Task t=ServiceAccess.GetTask();
if (t.TaskType == 1)
{
BrutalMemoryConsumerProcessor b=new BrutalMemoryConsumerProcessor();
b.DoTask(t);
}
else if (t.TaskType == 2)
{
HeavyCPUConsumerProcessor h=new HeavyCPUConsumerProcessor();
h.DoTask(t);
}
}
私にとって幸いなことにOutOfMemoryException
、内部コードのどこかで数サイクル後に停止しました。これは、両方のオブジェクトが存在する RAM のほぼすべてを使用するように調整されているため (x86 アプリの場合)、新しいインスタンスが作成されている間に古いオブジェクト インスタンスを保持することは、プロセスが確実に消滅する方法です。
わかりましたので、最初にいくつかのトリックを試しました。すなわち:
GC.Collect();
ループの最初、 の直後while (true)
。
運がない。
次に、昔の VB6 COM ベースの時代を思い出し、ステートメント ブロックのスコープ内で実行b = null;
してみました。h = null;
if
また運がない。
合わせて、サイコロなし。
メモリ プロファイラを起動しました。しばらく使用していなかったので、「プログラムファイル」のページを数ページ調べて見つける必要がありました. YourKit Profilerです。いいおもちゃ…
とにかく、それをいじった後、参照がローカルの「スタックスコープ」内にとどまってb
いることがわかりました。h
だから私は猿がすることをして、上記を次のように書き直しました:
while (true)
{
Task t=ServiceAccess.GetTask();
if (t.TaskType == 1)
{
DoTaskType1(t);
}
else if (t.TaskType == 2)
{
DoTaskType2(t);
HeavyCPUConsumerProcessor h=new HeavyCPUConsumerProcessor();
h.DoTask(t);
}
}
private void DoTask1(Task T)
{
BrutalMemoryConsumerProcessor b=new BrutalMemoryConsumerProcessor();
b.DoTask(T);
}
private void DoTask2(Task T)
{
HeavyCPUConsumerProcessor b=new HeavyCPUConsumerProcessor();
b.DoTask(T);
}
ああ、私の。メモリリークの問題を解決しました。
if
したがって、オブジェクトの作成を確実にスコープ外になる関数内に移動することで、コード ブロック自体がスコープであるにもかかわらず、オブジェクトが解放されて削除されました。
なんで?