まず最初に、実際に何が起こっているのかを追跡する必要があります。このような状況では、私の最初のツールは常にWinDbg です。
http://www.windbg.org/
http://en.wikipedia.org/wiki/WinDbg
マネージド/.NET コードで使用するには、SOS (Son of Strike) 拡張機能を使用する必要があります。
http://msdn.microsoft.com/en-us/library/bb190764.aspx
http://blogs.msdn.com/b/johan/archive/2007/11/13/getting-started-with-windbg-part-i.aspx
したがって、WinDbg を w3wp.exe プロセスにアタッチしたら、最初に行うことは、実際にヒープに何があるかを把握することです。
!dumpheap -stat
これにより、現在メモリ内にあるすべての「ライブ」オブジェクトの適切にフォーマットされたビューが、オブジェクトの種類ごとにグループ化されて、それらの数、占有されているバイト数と共に表示されます。
さて、ラージ オブジェクト ヒープ (LOH) - 通常、オブジェクトがガベージ コレクションされると、ハード ドライブの最適化のような圧縮が行われます。これにより、新しいオブジェクトの割り当てが高速かつ効率的に維持されます。問題は、大きなオブジェクトをコンパクトにするのは簡単ではないということです。それらを収容するためにすべてを移動する必要があります。そのため、85000 バイトを超えるものはすべて、Large Object Heap と呼ばれる特別な場所にスタックされます。このヒープは圧縮されていないため、時間の経過とともに、ハード ドライブと同じように断片化が発生し、ヒープ内に未使用のギャップが残り、ランタイムがより多くのスペースを必要とするようになります。
それでは、windbg に LOH の内容を教えてもらいましょう。
!dumpheap -stat -min 85000
これにより、Large Object Heap に実際にあるものが表示されます。これらのオブジェクトの一部は、List や MyClass[] のようにすぐに飛び出します。
重要: ラージ オブジェクト ヒープに表示されるものが意図的に長寿命である場合 (たとえば、ロガーの静的インスタンスなど)、実際には問題にはなりません。ただし、断片化を減らすために、存続期間が短い/頻繁に作成されるオブジェクトの数を抑えたいと考えています。
したがって、SOS 探索のチート シートをお勧めします。
http://windbg.info/doc/1-common-cmds.html
http://windbg.info/doc/2-windbg-az.html
楽しいコマンド:
!gcroot <address> <- will show you what object is "rooting" another
!CLRStack <- show current managed call stack
!dumpobj <address> <- show information about object at address
しかし、私のこれまでのお気に入りは次のとおりです。
bp clr!SVR::gc_heap::allocate_large_object "!CLRStack; g;"
大きなオブジェクト ヒープにオブジェクトを割り当てるときに CLR が使用する実際の内部呼び出しにブレークポイントを設定し、ヒットすると完全なスタック トレースをダンプしてから続行します。