3

私は、いくつかの重い処理を行い、多くのメモリを使用し、さらにそれを行う .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したがって、オブジェクトの作成を確実にスコープ外になる関数内に移動することで、コード ブロック自体がスコープであるにもかかわらず、オブジェクトが解放されて削除されました。

なんで?

4

1 に答える 1