簡體   English   中英

如何使用C#正確卸載AppDomain?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM