GC
によって収集されないファイナライズ可能なオブジェクトに関する問題が発生しました。 オブジェクトが
IDisposable
を実装している場合は、
Dispose()
を明示的に呼び出す必要がありますが、私はいつもフレームワークに依存することが安全であると考え、オブジェクトが参照されなくなったときに収集できると考えました。
しかし、私は、GC.SuppressFinalize()がファイナライズ可能オブジェクトに対して呼び出されなかった場合、それがルーティングされなくなっても収集されないことを発見しました。したがって、ファイナライズ可能なオブジェクト(DbConnection、FileStreamなど)を広範囲に使用し、それらを明示的に破棄しないと、メモリ消費量が多すぎるか、OutOfMemoryException
に遭遇することがあります。ここでファイナライザを使用しているオブジェクトが、ルーティングされていない場合でも収集されないのはなぜですか?
は、サンプルアプリケーションです:
public class MemoryTest
{
private HundredMegabyte hundred;
public void Run()
{
Console.WriteLine("ready to attach");
for (var i = 0; i < 100; i++)
{
Console.WriteLine("iteration #{0}", i + 1);
hundred = new HundredMegabyte();
Console.WriteLine("{0} object was initialized", hundred);
Console.ReadKey();
//hundred.Dispose();
hundred = null;
}
}
static void Main()
{
var test = new MemoryTest();
test.Run();
}
}
public class HundredMegabyte : IDisposable
{
private readonly Megabyte[] megabytes = new Megabyte[100];
public HundredMegabyte()
{
for (var i = 0; i < megabytes.Length; i++)
{
megabytes[i] = new Megabyte();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~HundredMegabyte()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
}
public override string ToString()
{
return String.Format("{0}MB", megabytes.Length);
}
}
public class Megabyte
{
private readonly Kilobyte[] kilobytes = new Kilobyte[1024];
public Megabyte()
{
for (var i = 0; i < kilobytes.Length; i++)
{
kilobytes[i] = new Kilobyte();
}
}
}
public class Kilobyte
{
private byte[] bytes = new byte[1024];
}
でも10回の反復の後、あなたはそのメモリ消費量は、(700メガバイトから1ギガバイトまで)が高すぎると、より多くの反復でさえ高くなる見つけることができます。 WinDBGを使用してプロセスにアタッチすると、すべてのラージオブジェクトはルーティングされていませんが、収集されません。
SuppressFinalize()
を明示的に呼び出すと状況が変わります。メモリ消費量は高圧下でも300〜400MB程度で安定しており、WinDBGはルーティングされていないオブジェクトがないことを示しています。
問題は次のとおりです。フレームワークのバグですか?論理的な説明はありますか?
詳細:ことを各反復後
、windbgのに示す:ファイナライズキューが空である
- freachableキューは
- 世代2は、前の反復からのオブジェクト(百)が含ま空である
- 以前の反復のオブジェクトは、ループされていません
私はそれを実行しようとしたが、私はそれを100mb程度まで削減した時点で700mbに達した。 (私はちょうどリターンを押し続け、タスクマネージャのメモリ使用量を見ていました)。 Windows 8を実行中。 – keyboardP
非常に興味深い...私はwin7 x64でテストしました。 1秒間停止して最初の10回の繰り返しをした後に、鍵を保持しています... outofmemory – 6opuc
もう一度試しましたが、例外なく100回繰り返しました。また、64ビット、かなり面白いです。たぶん誰かがテストして結果を投稿することもできます。 – keyboardP