ガベージコレクターは、.NETの非同期呼び出し中に一時的に参照されていないオブジェクトを破棄しますか?
-
05-07-2019 - |
質問
.NET、つまりHttpWebRequest.BeginGetResponseで非同期呼び出しを行い、HttpWebRequestオブジェクトがより広いスコープで参照されないことを想像してください。ガベージコレクターはそれを破壊して問題を引き起こしますか?
サンプルコード:
using System;
using System.Net;
public class AsyncHttpWebRequest
{
void Main()
{
var Request = HttpWebRequest.Create("http://www.contoso.com");
var result = Request.BeginGetResponse(GetResponseCallback, null);
}
private void GetResponseCallback(IAsyncResult AsyncResult)
{
// Do Something..
}
}
代替バージョン(リクエストがAsyncStateとして渡される):
using System;
using System.Net;
public class AsyncHttpWebRequest
{
void Main()
{
var Request = HttpWebRequest.Create("http://www.contoso.com");
var result = Request.BeginGetResponse(GetResponseCallback, Request);
}
private void GetResponseCallback(IAsyncResult AsyncResult)
{
// Do Something..
}
}
解決
オブジェクトは、ライブスレッドに参照が含まれている場合、または静的に(両方の場合に直接的または間接的に)参照されている場合、ガベージコレクションの対象と見なされます。
両方の例で、非同期APIはリクエストへの参照を保持します(非同期IO操作が保存されるスレッドプール内)。そのため、完了するまでガベージコレクションされません。
他のヒント
いいえ、ガベージコレクターは問題を引き起こしません。
あなたはオブジェクトにアクセスできないため、ガベージコレクターがオブジェクトをクリーンアップすると想定しないでください。
ガベージコレクターは、多くの「ルート」で始まります。 -到達可能なことがわかっているオブジェクトと参照。次に、それらのルートから到達可能なすべてのオブジェクトが検出され、他のすべてが収集されます。
実行中の各スレッド-非同期呼び出しを処理するスレッドを含むルートのリストに含まれます。
GCに関する限りオブジェクトに参照がない場合、そのオブジェクトへの参照を取得することはできなくなります。したがって、一時的にが参照を持たないオブジェクトを持つことはできません。
(これは、ゲームをプレイするアンマネージコードまたは安全でないコードのように卑劣なものを想定していない)
非同期呼び出しの実装により、オブジェクトは正常に参照されたままになります。これは、開いているすべてのリクエストのリストを保持し、着信データをリクエストに関連付ける必要があります。ほとんどの場合、.NETはグローバル(またはクラス)変数を使用してリクエストを保存します。
最初のサンプルコードでは、使用しないのに、なぜRequestを作成するのですか?
とにかく、現在スコープ内にあるオブジェクトからオブジェクトへの参照(直接または間接)が存在しない場合、GCは 収集します。
したがって、最初の例では、プログラムが終了すると、メインメソッドRequestはまだスコープ内(別のスレッド内)にあるため、非同期呼び出しが終了するまで収集されません。 2番目の例では、スレッドプールスレッドとコードの両方がオブジェクトへの参照を保持するため、明らかに同様に収集されません。