Domanda

Sulla base di tutte le mie letture dovrebbe esserci un thread GC per invocare tutti i finalizzatori. Ora, la domanda è qual è lo scopo di questo "uno" thread - per processo o per dominio di applicazione, poiché l'intera intenzione dei domini è di separare e rendere "indipendente" diverse applicazioni in un unico spazio di processo.

Ho letto qui :

  

Se si verifica un'eccezione non gestita in a   finalizzatore del thread di esecuzione del CLR   inghiottirà l'eccezione, tratterà il   finalizzatore come se si completasse normalmente,   rimuoverlo dalla coda freachable   e passare alla voce successiva.

     

Più serio, però, è ciò che accade   se il tuo finalizzatore non esce   qualche motivo, ad esempio blocca,   aspettando una condizione che mai   si verifica. In questo caso il finalizzatore   il filo verrà appeso, quindi non di più   gli oggetti finalizzabili saranno immondizia   raccolti. Dovresti essere molto   consapevole di questa situazione e attenersi   scrivendo il codice più semplice per liberare il tuo   risorse non gestite nei finalizzatori.

     

Un'altra considerazione è ciò che accade   durante l'arresto dell'applicazione. Quando il   il programma viene chiuso, il Garbage Collector   cercherò di chiamare i finalizzatori   di tutti gli oggetti finalizzabili, ma con   alcune limitazioni:

     
      
  • Gli oggetti finalizzabili non sono promossi   alle generazioni di heap superiori durante   shutdown.

  •   
  • Ogni singolo finalizzatore avrà un   massimo 2 secondi da eseguire; se è così   impiega più tempo a essere ucciso.

  •   
  • C'è un massimo di 40 secondi per   tutti i finalizzatori da eseguire; se presente   i finalizzatori sono ancora in esecuzione, oppure   in attesa a questo punto del tutto   il processo viene improvvisamente interrotto.

  •   

Troppi post (e persino documentazione ufficiale) uso improprio dei termini "applicazione", "elaborazione". e "dominio applicazione" - la maggior parte di loro suppone anche che siano uguali, perché di solito le applicazioni vengono eseguite in un singolo dominio dell'applicazione in un singolo processo. Questo uso improprio rende tutti questi documenti difficili da leggere e nemmeno utili.

Quindi, la mia domanda presuppone più di una applicazione, ciascuna eseguita in un dominio di applicazione separato in un singolo processo.

Tutte queste applicazioni condividono gli stessi thread GC e finalizzatore? Il problema descritto nell'articolo precedente (blocco thread finalizzatore) influirà su tutte le applicazioni in quel processo? Se sì, esiste una soluzione alternativa (oltre a non utilizzare applicazioni non valide), come in qualche modo scoprire il thread del finalizzatore e inviarlo Thread.Abort?

Tutto quanto sopra è perché ho riscontrato un problema simile. La mia applicazione viene eseguita in un dominio applicazione separato come componente aggiuntivo a software di terze parti (Outlook). Per vari motivi, devo chiamare GC.Collect e GC.WaitForPendingFinalizers per rilasciare completamente i riferimenti COM (le solite routine di interoperabilità non sono sufficienti per Office / Outlook), quando un particolare componente aggiuntivo di terze parti è in esecuzione, il mio GC.WaitForPendingFinalizers si blocca per sempre , quindi sospetto che ci sia un "cattivo" finalizzatore nell'aggiunta di tale terza parte. Non ho alcun controllo sulla sostituzione / rimozione di tale aggiunta (requisito del cliente), quindi devo capire da solo come farli coesistere.

È stato utile?

Soluzione

Sembra che sia effettivamente solo un thread per istanza CLR all'interno del processo - al momento, comunque. Ecco un po 'di codice per mostrare che:

Test.cs:

using System;

class Test
{
    static void Main()
    {
        AppDomain.CreateDomain("First")
                 .ExecuteAssembly("ShowFinalizerThread.exe");
        AppDomain.CreateDomain("Second")
                 .ExecuteAssembly("ShowFinalizerThread.exe");
    }
}

ShowFinalizerThread.cs:

using System;
using System.Threading;

class ShowFinalizerThread
{
    static Random rng = new Random();

    ~ShowFinalizerThread()
    {
        Console.WriteLine("Thread/domain: {0}/{1}",
                          Thread.CurrentThread.ManagedThreadId,
                          AppDomain.CurrentDomain.FriendlyName);
        if (rng.Next(10) == 0)
        {
            Console.WriteLine("Hanging!");
            Thread.Sleep(2000);
        }
    }

    static void Main()
    {
        new Thread(LoopForever).Start();
    }

    static void LoopForever()
    {
        while (true)
        {
            new ShowFinalizerThread();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            Thread.Sleep(300);
        };
    }
}

Compilare ciascuno come app console, quindi eseguire test.exe (dalla riga di comando è più semplice, IMO). Vedrai che il finalizzatore di un dominio di app ne blocca un altro.

In futuro non sarei sorpreso di vedere un thread finalizzatore per core piuttosto che per AppDomain - ma sembra che avrai ancora problemi :(

Hai la mia più profonda simpatia (anche se non una soluzione) - una volta ho rintracciato un punto morto in un BLOB Oracle. Siamo riusciti a risolverlo eliminandolo correttamente, ma so che non tutto funziona così bene - ed è stato un vero dolore persino trovarlo!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top