前回の記事
[Memo] デストラクタが呼ばれるタイミングの検証 その1
前回の検証で、デストラクタが走るタイミングは、必ずしもクラスを使い終わったときと限らないことがわかりました。
そこで、こんどは GC.Collectメソッドを使用して強制的にガベージコレクションを実行し、デストラクタが呼ばれるかを検証してみました。
前回の Program.cs にある CreateSampleメソッドを以下のように書き換えます。
これで、GC.Collectによって強制的にガベージコレクションが実行されるので、デストラクタは「Sampleのインスタンス生成終了」の文字の前に実行されるはずです。
static void CreateSample() { Console.WriteLine("Sampleのインスタンス生成"); new Sample(); GC.Collect(); Console.WriteLine("Sampleのインスタンス生成終了"); }
実行結果は以下の通りです。
あれ?前回と変わらない….
確かに、ガベージコレクションは強制的に実行されるのですが、ガベージコレクションが実行されるタイミングと次に実行される命令との間で同期はとられないようです。
同期をとるには(というよりガベージコレクションが終了するのを待つには)、GC.WaitForPendingFinalizersメソッドを呼び出す必要があります。
そこで、 GC.Collectの実行後に GC.WaitForPendingFinalizersメソッドを呼び出すように書き換えてみます。
static void CreateSample() { Console.WriteLine("Sampleのインスタンス生成"); new Sample(); GC.Collect(); GC.WaitForPendingFinalizers(); Console.WriteLine("Sampleのインスタンス生成終了"); }
実行結果は以下の通りです。
今度は、ガベージコレクションの実行が終わるのを待つので、デストラクタが呼び出された後に「Sampleのインスタンス生成終了。」が表示されています。
以上のように、GC.Collectを実行したからと言って必ずしもオブジェクトが破棄されてから次の命令が実行されるわけではありません。
また、前回も述べたとおり、クラスを使い終わったからと言って、即デストラクタが呼び出されるわけでもありません。
(この辺がガベージコレクションの仕組みで、オブジェクトが不要になったのを見計らって破棄を実施するので、そのタイミングはいつなのかはわかりません)
オブジェクトの破棄のタイミングは、 GC.Collectメソッドで決めることができますが、場合によっては GC.WaitForPendinGinalizersメソッドが必要だということを覚えておきましょう。
基本的に、ガベージコレクションは自動で実行されるため、このような場面に遭遇するのはあまり多くはないと思います。
コメント