2008-10-27 5 views
15

Основываясь на всех моих чтениях, должен быть один поток GC для вызова всех финализаторов. Теперь вопрос заключается в том, какова область применения этого «одного» потока - для каждого процесса или для домена приложения, поскольку все намерение доменов заключается в разделении и создании «независимых» разных приложений в одном пространстве процесса.Какова область действия финализатора - для домена приложения или для каждого процесса?

Я прочитал here:

Если необработанное исключение происходит в финализаторе СЬК осуществляющем нить проглотит исключение, лечить финализации, как будто это нормально завершено, удалить его из freachable очереди и перейдите к следующей записи.

Более серьезным, хотя, это то, что происходит если ваш финализации не выход для какой-то причине, например, он блокирует, ждет условие, которое никогда не происходит. В этом случае резьба финализатора будет висела, поэтому не более объектов, подлежащих окончательному окончанию, будет мусором собран. Вам должно быть очень хорошо знать об этой ситуации и придерживаться написания простейшего кода, чтобы освободить неуправляемых ресурсов в финализаторах.

Другое соображение - это то, что происходит во время выключения приложения. Когда программа закрывает, сборщик мусор будет стремиться, чтобы вызвать Финализаторы всех финализируемых объекты, но с определенными ограничениями :

  • финализируемых объекты не раскручен в высшие поколения кучи во время выключения.

  • Любой отдельный финализатор будет иметь максимум 2 секунды для выполнения; если он займет больше времени, он будет убит.

  • Для существует не более 40 секунд всех финализаторов, которые должны быть выполнены; если какие-либо финализаторы все еще выполняются, или ожидает, что на данный момент весь процесс внезапно уничтожен.

Слишком много сообщений (и даже официальная документации) злоупотребления терминов «применение», «процесс» и «домен приложения» - большинство из них даже при условии, что они равны, потому что обычно приложения запускаются в одном домене приложения в одном процессе. Это неправильное использование делает все эти документы трудными для чтения и даже не полезно.

Итак, мой вопрос предполагает использование нескольких приложений, каждый из которых выполняется в отдельном домене приложения в одном процессе.

Содержит ли все эти приложения одни и те же потоки GC и финализатора? Означает ли проблема, описанная в статье выше (зависает поток финализатора), затронет все приложения в этом процессе? Если да - есть ли способ обхода (кроме того, чтобы не использовать плохие приложения), как-то обнаружить поток финализатора и отправить ему Thread.Abort?

Все выше, потому что я ударил аналогичную проблему. Мое приложение работает в отдельном домене приложения как дополнение к стороннему программному обеспечению (Outlook). Из-за различных причин мне нужно вызвать GC.Collect и GC.WaitForPendingFinalizers для полного выпуска ссылок COM (обычных процедур взаимодействия недостаточно для Office/Outlook), когда работает какая-либо другая сторонняя добавка, мой GC.WaitForPendingFinalizers висит навсегда , поэтому я подозреваю, что в этой третьей стороне есть «плохой» финализатор. У меня нет контроля над заменой/удалением этого добавления (требование клиента), поэтому я должен сам выяснить, как сделать их совместными.

+0

+1 для ясного и подробного вопроса – Basic 2010-12-13 17:28:32

ответ

8

Похоже, что это действительно один поток на экземпляр CLR в процессе - в данный момент, во всяком случае. Вот код, чтобы показать, что:

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

Заполнять каждый как приложение консоли, а затем запустить test.exe (из командной строки является самым простым, ИМО). Вы увидите, что финализатор одного домена домена блокирует другой.

В будущем я бы не удивился, увидев один финализации нить на ядра, а не за AppDomain - но это звучит, как вы по-прежнему есть проблемы :(

У вас есть мое глубокое сочувствие (хотя а не решение) - как только я выследил тупик в Oracle Blob. Мы смогли исправить это, избавив его от этого, но я знаю, что не все работает так красиво - и это была настоящая боль даже при поиске этого!

+0

Я считаю, что это один поток для экземпляра CLR. Начиная с 2.0 и silverlight, теперь у вас может быть более одного CLR за процесс. – JaredPar 2009-02-10 00:38:43