制御できない外部アセンブリをロードするアプリケーションがあります(他の人がメインアプリケーションで使用されるアセンブリを作成および開発するプラグインモデルに似ています)。これらのアセンブリの新しいAppDomainを作成してロードし、アセンブリの使用が完了すると、メインのAppDomainがそれらをアンロードします。
現在、単純に nloads これらのアセンブリは
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch(Exception exception)
{
// log exception
}
ただし、場合によっては、特にアンロードプロセス中に例外がスローされます CannotUnloadAppDomainException
。私の理解では、子AppDomainsのスレッド アンマネージコードがまだ実行されているか、スレッドがfinally
ブロックにあるため、強制的に中止できないため :
スレッドがUnloadを呼び出すと、ターゲットドメインはアンロード用にマークされます。専用スレッドがドメインのアンロードを試み、ドメイン内のすべてのスレッドが中止されます。アンマネージコードを実行している、またはfinallyブロックを実行しているなどの理由でスレッドが異常終了しない場合、一定期間後、元々Unloadを呼び出したスレッドでCannotUnloadAppDomainExceptionがスローされます。中止できなかったスレッドが最終的に終了した場合、ターゲットドメインはアンロードされません。したがって、.NET Frameworkバージョン2.0では、実行中のスレッドを終了できない可能性があるため、ドメインのアンロードは保証されません。
私の懸念は、アセンブリがロードされていない場合、メモリリークが発生する可能性があることです。考えられる解決策は、上記の例外が発生した場合にメインアプリケーションプロセス自体を強制終了することですが、私はむしろこの抜本的なアクションを回避します。
また、アンロードの呼び出しを数回繰り返すことも検討していました。おそらく、次のような制約付きループです。
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (CannotUnloadAppDomainException exception)
{
// log exception
var i = 0;
while (i < 3) // quit after three tries
{
Thread.Sleep(3000); // wait a few secs before trying again...
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (Exception)
{
// log exception
i++;
continue;
}
break;
}
}
これは意味がありますか?もう一度アンロードしようと気にする必要がありますか?一度試して先に進むべきですか?他にやるべきことはありますか?また、スレッドがまだ実行されている場合に、メインのAppDomainから外部アセンブリを制御するために実行できることはありますか(他の人がこの外部コードを記述して実行していることに注意してください)。
複数のAppDomainを管理する際のベストプラクティスを理解しようとしています。
私は自分のアプリで同様の問題に対処しました。基本的に、AppDomain
を強制的にダウンさせるためにUnload
よりも多くのことを行うことはできません。
基本的には、AppDomain
でコードを実行しているすべてのスレッドの中止を呼び出します。そのコードがファイナライザーまたはアンマネージコードでスタックしている場合、実行できることはほとんどありません。
問題のプログラムに基づいて、ファイナライザー/アンマネージコードが後で終了する可能性が高い場合は、絶対にUnload
を再度呼び出すことができます。そうでない場合は、意図的にドメインをリークするか、プロセスを循環させることができます。
ドメインをアンロードしない場合は、GC.Collect()を作成してみてください。
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch (CannotUnloadAppDomainException)
{
GC.Collect();
AppDomain.Unload(otherAssemblyDomain);
}