Il modo corretto per scaricare un AppDomain utilizzando C#?

Ho un’applicazione che carica assembly esterni che non ho alcun controllo su (simile a un plugin modello in cui la gente a creare e sviluppare le assemblee che vengono utilizzati dal programma principale). Carica attraverso la creazione di nuovi domini applicazioni per questi assemblaggi e poi, quando le assemblee sono fatto, la principale AppDomain li scarica.

Attualmente, è semplicisticamente scarica queste assemblee da

try
{
    AppDomain.Unload(otherAssemblyDomain);
}
catch(Exception exception)
{
    //log exception
}

Tuttavia, in alcuni casi, le eccezioni generate durante il processo di scarico appositamente CannotUnloadAppDomainException. Da quello che ho capito, questo può essere previsto in quanto un thread in bambini Appdomain non può essere forzatamente interrotta a causa di situazioni in cui il codice non gestito è ancora in fase di esecuzione o il thread è in un finalmente blocco:

Quando un thread chiama Scaricare, il target
dominio è contrassegnato per lo scarico. Il
thread dedicato tenta di scaricare
il dominio, e tutti i thread in
dominio sono interrotto. Se un thread
non abortire, per esempio, perché è
l’esecuzione di codice non gestito, o perché
è l’esecuzione di un blocco finally, quindi
dopo un periodo di tempo di un
CannotUnloadAppDomainException è
gettato nel thread che originariamente
chiamato Scaricare. Se il thread
potrebbe non essere interrotto alla fine finisce,
il dominio di destinazione non viene scaricato.
Così, nella .NET Framework versione
2.0 dominio non è garantito per scaricare, perché potrebbe non essere
possibile terminare l’esecuzione di
thread.

La mia preoccupazione è che, se l’assemblea non viene caricato, quindi potrebbe causare una perdita di memoria. Una possibile soluzione sarebbe quella di uccidere il principale processo di applicazione della stessa, se l’eccezione di cui sopra si verifica, ma preferisco evitare questo drastico intervento.

Stavo anche valutando di ripetere le operazioni di scarico di chiamata per un paio di altri tentativi. Forse un vincolata loop come questo:

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;
    }
}

Questo ha senso? Dovrei nemmeno la briga di provare a scaricare di nuovo? Devo solo provare una volta e spostare? C’è qualcos’altro che posso fare? Inoltre, c’è qualcosa che può essere fatto dal principale dominio di applicazione per controllare il montaggio esterno se i thread sono ancora in esecuzione (tenere in mente gli altri sono la scrittura e l’esecuzione di questo codice esterno)?

Sto cercando di capire quali sono le best practice per la gestione di più domini applicazioni.

  • Questo è irrefutabile. Se si dispone di alcun controllo sul thread in app quindi non c’è motivo di speranza che uno di quei fili d’improvviso, cooperare 3 secondi più tardi. Isolarlo in un processo che è l’unica vera correzione.
  • Grazie Hans. Suona come questo è una limitazione di Appdomain rispetto ai processi. Speravo fosse un modo per forzare l’uccidere un dominio di applicazione, in qualsiasi circostanza, esattamente come per forza uccidere un processo (come hai suggerito).
  • Non isolare l’esecuzione di un processo dedicato davvero garantire questo può essere evitato?
  • Processo.Kill (), funziona sempre.
InformationsquelleAutor Ray Vega | 2010-12-13

 

2 Replies
  1. 10

    Ho avuto a che fare con un problema simile nel mio app. Fondamentalmente, si può fare qualcosa di più per forzare il AppDomain per andare giù di Unload fa.

    Fondamentalmente, si chiama interruzione di tutti i thread in esecuzione di codice in AppDomain, e se il codice che è bloccato in un finalizzatore o codice non gestito, non c’è molto che può essere fatto.

    Se, in base al programma in questione, è probabile che il finalizzatore/codice non gestito, per finire un secondo momento, si può assolutamente chiamare Unload di nuovo. Se non, si può perdere il dominio di scopo o di ciclo di processo.

  2. 0

    Provare a fare il GC.Raccogliere() se non scaricare il dominio.

     try
        {
           AppDomain.Unload(otherAssemblyDomain);
        }
        catch (CannotUnloadAppDomainException)
        {
           GC.Collect();
           AppDomain.Unload(otherAssemblyDomain);
        }

Lascia un commento