[英]How to properly unload an AppDomain using C#?
我有一個應用程序加載我無法控制的外部程序集(類似於其他人創建和開發主應用程序使用的程序集的插件模型)。 它通過為這些程序集創建新的AppDomain來加載它們,然后在使用程序集完成后,主AppDomain將卸載它們。
目前,它簡單地卸載這些程序集
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch(Exception exception)
{
// log exception
}
但是,有時會在卸載過程中拋出異常,特別是CannotUnloadAppDomainException
。 根據我的理解,這是可以預料到的,因為由於非托管代碼仍在執行或線程在finally
塊中的情況,子域AppDomains中的線程無法強制中止 :
當線程調用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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.