this
仮想メソッド ディスパッチでは少し複雑になりますが、インスタンス メソッドは、最初のパラメーターとして渡される静的メソッドとほぼ同じように動作します。したがって、 class 内Foo
で、フィールドint Bar
にはメソッドがあります
void SetBar(int newBar) { Bar = newBar; }
内部的には次と同等です。
static void SetBar(Foo This, int newBar) { This.Bar = newBar; }
アンマネージ ビットマップへのハンドルを保持し、次のようなメソッドをFoo
持つフィールドが呼び出されたとします。MyBitmap
IntPtr
// Should call GC.SuppressFinalize, but doesn't.
static Byte[] ExportBitmapDataAndDispose(Foo This)
{
IntPtr myBits = This.MyBitMap;
if (myBits == 0) throw new ObjectDisposedException(...);
int destSize = ExternalBitmapHandler.GetSize(myBits);
var result = new Byte[destSize];
ExternalBitmapHandler.CopyBits(myBits, ref result[0], destSize);
ExternalBitmapHandler.ReleaseBits(myBits);
myBits = 0;
}
コンパイラはThis
、フィールドMyBitMap
が読み取られた後、それが使用されていないことを認識します。コードは で識別される外部リソースを必要としますmyBits
が、ガベージ コレクターはそのようなことを何も知りません。その観点からは、によって参照されるオブジェクトにThis
他のライブ参照がない場合、コードは、それらのオブジェクトがその時点で単に存在しなくなったのか、それともそれより長く保持されていたのかを気にする必要はありません。実際、実行中のコードはそのようなオブジェクトがいつ存在しなくなったかを実際に気にしないという点で、その仮定は正しいです。残念ながら、ファイナライザーが存在する場合、オブジェクトは単に存在しなくなるわけではありません。代わりに、ファイナライゼーション キューが への唯一のライブ参照を保持していることにガベージ コレクターが気付いた場合、ガベージ コレクターThis
は実行This.Finalize()
中の可能性があります。ExternalBitmapHandler
によって識別されたビットマップmyBits
はもはや必要ありません。
問題は実際には のガベージ コレクションでThis
はなく、 のファイナライズにあることに注意してくださいThis
。ファイナライズはガベージ コレクションではなく、代わりに、登録されたファイナライザーが対象でなかった場合に即時消滅の対象となるオブジェクトを GC が検出したときにトリガーされる操作です。別の見方をすると、 でExternalBitmapHandler
識別されるビットマップThis.MyBitMap
が不要になったときに に通知する必要がありますが、ガベージ コレクターが伝えることができる唯一のことは、This
が不要になったときです。コードが に読み込まThis.MyBitMap
れるmyBits
と、それはもう必要This
ありません。This
「myBits. コードの代替バージョンは次のようになります。
static Byte[] ExportBitmapDataAndDispose(Foo This)
{
IntPtr myBits = System.Threading.Interlocked.Exchange(ref This.MyBitMap, 0);
GC.SuppressFinalize(This);
if (myBits == 0) throw new ObjectDisposedException(...);
int destSize = ExternalBitmapHandler.GetSize(myBits);
try
{
var result = new Byte[destSize]; // Could throw OutOfMemoryException
ExternalBitmapHandler.CopyBits(myBits, ref result[0], destSize);
}
finally
{
ExternalBitmapHandler.ReleaseBits(myBits);
}
}
この場合、 がなくKeepAlive
、SuppressFinalize
すべてが完了するまでファイナライズの可能性を延期するコードが最後に配置されていないことに注意してください。が発生するInterlocked.Exchange
と、システムが を破棄しても何の問題もありThis
ません。システムは、実行するのに十分な時間それを保持する必要がありますSuppressFinalize
が、その後は消えて誰も気付かない可能性があります.