全体的な問題
メモリ使用量をカウントしてレポートする試みは、測定されていた GC オブジェクト割り当てサイズの 10,000 倍のメモリを消費する方法で処理されました。
さらに、ハンドル数の出力は目前の問題には適用できませんでしたが (テストではハンドルが開閉されていなかったため)、大量のメモリ割り当てが発生しました (その数だけを削除すると、割り当ての合計が半分になりました)。
元のプログラムは、60 ~ 120 バイトのオブジェクトの割り当てを測定しようとしていましたが (32 ビット プログラムか 64 ビット プログラムかによって異なります)、呼び出されるたびに 600 KB のメモリが割り当てられる関数を使用して測定しましたそのうち、ラージ オブジェクト ヒープ (LOH) にありました。
これをテストする別の方法が提供されています。これは、GC.Collect 呼び出しの後にすべてのオブジェクトが実際になくなったことを示しています。DisplayMemory 関数のメモリ使用量の詳細も提供されます。
結論
100k オブジェクトを作成して収集しても、マネージ メモリのサイズは増加しません。5 つのオブジェクトのみが作成および収集されると、プロセスのプライベート バイトは約 12 KB 増加しますが、SoS は、それがマネージド ヒープからのものではないことを示しています。非常に小さいサイズとオブジェクト数を扱っている場合、何が起こっているのかを正確に判断することはできません。代わりに、非常に多数のオブジェクトでテストして、何かがリークしているかどうかを非常に簡単に確認できるようにすることをお勧めします。この場合、漏れはなく、何も問題はなく、すべて問題ありません。
分析ツールとアプローチ
このプログラムによるメモリ使用量を確認するために、次の 2 つのツールを使用しました。
- VS 2013 Pro - パフォーマンスおよび診断ツール - 最初にこれを実行したところ、元のプログラムが 3.6 MB のメモリを割り当てていることがわかりました。これは、オブジェクトの割り当てから予想される 60 ~ 120 バイトだけではありません。文字列とコンソールへの書き込みでメモリがいくらか使用されることはわかっていましたが、3.6 MB はショックでした。
- Son of Strike (SoS) - これは、Visual Studio および WinDbg で動作するデバッガ拡張機能であり、.Net Framework に同梱されています (マシンの各フレームワーク バージョン ディレクトリにある sos.dll を参照してください)。
VS 2013 Pro - パフォーマンスおよび診断ツール - メモ
「プロファイリング方法」を「.NET メモリ割り当て」に設定して、VS 2013 Pro のパフォーマンスおよび診断ツールで元のプログラムを実行した結果を以下に示します。これにより、考えられていたよりも多くのメモリが割り当てられているという非常に簡単な手がかりが得られました。グラフの上にある 3.6 MB の合計割り当てを参照してください。DisplayMemory 呼び出しを削除すると、2,476 バイトに減少します。

ストライクの息子 - メモ
マシンに .Net 4.5 がインストールされていない限り、VS2010 で SoS を使用できます。または、Update3 を使用して VS2012 で使用できます。プロジェクトでアンマネージド デバッグを有効にし、32 ビット プロセスを開始していることを確認してから、VS デバッガーのイミディエイト ウィンドウで ".load sos" を実行してください。この問題を確認するために使用したコマンドは、「!eeheap -gc」と「!dumpheap -stat」です。
代替試験プログラム
class Program
{
static void Main()
{
// A few objects get released by the initial GC.Collect call - the count drops from 108 to 94 objects in one test
GC.Collect();
// Set a breakpoint here, run these two sos commands:
// !eeheap -gc
// !dumpheap -stat
for (int i = 0; i < 100000; i++)
{
object o = new object();
}
// Set a breakpoint here, run these two sos commands before this line, then step over and run them again
// !eeheap -gc
// !dumpheap -stat
GC.Collect();
}
}
代替テスト結果
概要
100,000 個の System.Object を割り当てて収集すると、最初より 4 個少ないオブジェクトになり、マネージド ヒープ サイズは最初より 900 バイト小さくなります。
ガベージ コレクションは期待どおりに機能しています。
ベースライン - 最初の GC.Collect の後
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x024f23d0
generation 1 starts at 0x024f100c
generation 2 starts at 0x024f1000
ephemeral segment allocation context: none
segment begin allocated size
024f0000 024f1000 024f23dc 0x13dc(5084)
Large object heap starts at 0x034f1000
segment begin allocated size
034f0000 034f1000 034f5380 0x4380(17280)
Total Size: Size: 0x575c (22364) bytes.
------------------------------
GC Heap Size: Size: 0x575c (22364) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed026b8 1 112 System.AppDomain
6ed025b0 2 168 System.Threading.ThreadAbortException
6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
6ed03a6c 2 380 System.Int32[]
6ed0349c 20 560 System.RuntimeType
0047fab8 14 1024 Free
6ed02248 32 1692 System.String
6ecefe88 6 17340 System.Object[]
Total 95 objects
100,000 個の System.Object を割り当てた後、最終的な GC.Collect の前
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x024f23d0
generation 1 starts at 0x024f100c
generation 2 starts at 0x024f1000
ephemeral segment allocation context: none
segment begin allocated size
024f0000 024f1000 02617ff4 0x126ff4(1208308)
Large object heap starts at 0x034f1000
segment begin allocated size
034f0000 034f1000 034f5380 0x4380(17280)
Total Size: Size: 0x12b374 (1225588) bytes.
------------------------------
GC Heap Size: Size: 0x12b374 (1225588) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed024e4 1 84 System.OutOfMemoryException
6ed02390 1 84 System.Exception
6ed026b8 1 112 System.AppDomain
6ed025b0 2 168 System.Threading.ThreadAbortException
6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
6ed03a6c 2 380 System.Int32[]
6ed0349c 20 560 System.RuntimeType
0047fab8 14 1024 Free
6ed02248 32 1692 System.String
6ecefe88 6 17340 System.Object[]
6ed025e8 100002 1200024 System.Object
Total 100095 objects
最終GC.Collect後
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x024f2048
generation 1 starts at 0x024f2030
generation 2 starts at 0x024f1000
ephemeral segment allocation context: none
segment begin allocated size
024f0000 024f1000 024f2054 0x1054(4180)
Large object heap starts at 0x034f1000
segment begin allocated size
034f0000 034f1000 034f5380 0x4380(17280)
Total Size: Size: 0x53d4 (21460) bytes.
------------------------------
GC Heap Size: Size: 0x53d4 (21460) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed024e4 1 84 System.OutOfMemoryException
6ed02390 1 84 System.Exception
6ed026b8 1 112 System.AppDomain
0047fab8 9 118 Free
6ed025b0 2 168 System.Threading.ThreadAbortException
6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
6ed03a6c 2 380 System.Int32[]
6ed0349c 20 560 System.RuntimeType
6ed02248 32 1692 System.String
6ecefe88 6 17340 System.Object[]
Total 91 objects
DisplayMemory 関数のメモリ使用量のレビュー
System.Object の割り当てと比較すると、DisplayMemory はメモリを大量に消費します。文字列 (ヒープ上に置かれる) を作成しており、メモリを取得するために呼び出す関数は、それ自体で大量 (約 600 KB) のメモリを使用しています。
DisplayMemory を呼び出す前のメモリ使用量
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x02321018
generation 1 starts at 0x0232100c
generation 2 starts at 0x02321000
ephemeral segment allocation context: none
segment begin allocated size
02320000 02321000 02323ff4 0x2ff4(12276)
Large object heap starts at 0x03321000
segment begin allocated size
03320000 03321000 03325380 0x4380(17280)
Total Size: Size: 0x7374 (29556) bytes.
------------------------------
GC Heap Size: Size: 0x7374 (29556) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed05d3c 3 468 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
6ed0349c 20 560 System.RuntimeType
6ed02248 38 2422 System.String
6ecefe88 6 17340 System.Object[]
Total 102 objects
DisplayMemory を呼び出した後のメモリ使用量
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x023224fc
generation 1 starts at 0x023224f0
generation 2 starts at 0x02321000
ephemeral segment allocation context: none
segment begin allocated size
02320000 02321000 02371ff4 0x50ff4(331764)
Large object heap starts at 0x03321000
segment begin allocated size
03320000 03321000 033653c0 0x443c0(279488)
Total Size: Size: 0x953b4 (611252) bytes.
------------------------------
GC Heap Size: Size: 0x953b4 (611252) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed02c08 9 954 System.Char[]
006dfac0 17 1090 Free
6ed03aa4 156 1872 System.Int32
6ecffc20 152 3648 System.Collections.ArrayList
6ed05ed4 9 7776 System.Collections.Hashtable+bucket[]
7066e388 152 16416 System.Diagnostics.ProcessInfo
6ed02248 669 20748 System.String
706723e4 152 29184 System.Diagnostics.NtProcessInfoHelper+SystemProcessInformation
6ecefe88 463 48472 System.Object[]
706743a4 2104 75744 System.Diagnostics.ThreadInfo
70666568 2104 151488 System.Diagnostics.NtProcessInfoHelper+SystemThreadInformation
6ed0d640 2 262168 System.Int64[]
Total 6132 objects