私は GC とファイナライズについて学習し始めています。アプリケーションの動作が私にとってまったく予想外である、非常に単純な例に出くわしました。
(注: ファイナライザーは管理されていないリソースでのみ使用し、使い捨てパターンを使用する必要があることを認識しています。ここで何が起こっているのかを理解したいだけです。)
これは、「ノコギリ」パターンのメモリを生成するシンプルなコンソール アプリです。メモリは約 90MB まで上昇してから GC を実行し、低下してから再び上昇し始め、90MB を超えることはありません。
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 100000; i++)
{
MemoryWaster mw = new MemoryWaster(i);
Thread.Sleep(250);
}
}
}
public class MemoryWaster
{
long l = 0;
long[] array = new long[1000000];
public MemoryWaster(long l)
{
this.l = l;
}
//~MemoryWaster()
//{
// Console.WriteLine("Finalizer called.");
//}
}
ファイナライザーでコメントを削除すると、動作が大きく異なります。アプリケーションは開始時に 1 つまたは 2 つの GC を実行しますが、メモリは 1 GB を超えるメモリを使用するまで直線的に増加します (その時点でアプリケーションを終了します)。 )
私が読んだことから、これはアイテムを解放する代わりに、GC がオブジェクトをファイナライズ キューに移動するためです。GC はスレッドを開始してファイナライザー メソッドを実行し、別の GC がファイナライズされたオブジェクトを削除するのを待ちます。これは、ファイナライザー メソッドの実行時間が非常に長い場合に問題になる可能性がありますが、ここではそうではありません。
数回の反復ごとに GC.Collect() の実行を手動でトリガーすると、アプリは期待どおりに動作し、メモリの鋸歯状のパターンが解放されます。
私の質問は、アプリケーションによって使用されている大量のメモリが GC を自動的にトリガーしないのはなぜですか? ファイナライザーが含まれている例では、GC が最初に実行された後に再度実行されることはありますか?