Какова область действия финализатора - для домена приложения или для каждого процесса?
Основываясь на всех моих чтениях, должен быть один поток GC для вызова всех финализаторов. Теперь вопрос заключается в том, какова область действия этого "одного" потока - для каждого процесса или для каждого домена приложения, поскольку все намерение доменов состоит в том, чтобы разделить и сделать "независимые" различные приложения в одном пространстве процесса.
Я прочитал здесь:
Если необработанное исключение возникает в финализатор потока выполнения CLR проглотит исключение, финализатор, как если бы он завершился нормально, удалите его из свободной очереди и перейдите к следующей записи.
Более серьезно, что происходит если ваш финализатор не выходит по какой-то причине, например, он блокирует, ожидая условия, которые никогда не имеет место. В этом случае финализатор нить будет висела, так что больше нет финализируемые объекты будут мусором собрано. Ты должен быть очень осознавая эту ситуацию и придерживайтесь написав простейший код, чтобы освободить неуправляемые ресурсы в финализаторах.
Еще одно соображение - это то, что происходит во время выключения приложения. Когда программа отключается, сборщик мусора будут пытаться назвать финализаторы всех конечных объектов, но с определенные ограничения:
-
Конечные объекты не рекламируются к более высоким поколениям кучи во время завершение работы.
-
Любой отдельный финализатор будет иметь максимум 2 секунды для выполнения; если оно занимает больше времени, он будет убит.
-
Максимум 40 секунд для все финализаторы должны быть выполнены; если таковые имеются финализаторы все еще выполняются или ожидая в этот момент процесс внезапно уничтожается.
Слишком много сообщений (и даже официальная документация) неправильное использование терминов "приложение", "процесс" и "домен приложения" - большинство из них даже полагают, что они равны, поскольку обычно приложения запускаются в одном домене приложения в единый процесс. Это неправильное использование делает все эти документы трудными для чтения и даже не полезно.
Итак, мой вопрос предполагает более одного приложения, каждый из которых выполняется в отдельном домене приложения в одном процессе.
Все ли эти приложения используют одни и те же потоки GC и финализатора? Означает ли проблема, описанная в статье выше (зависает поток финализатора), затронет все приложения в этом процессе? Если да - есть ли способ обхода (кроме того, чтобы не использовать плохие приложения), как-то обнаружить поток финализатора и отправить его Thread.Abort?
Все выше, потому что я ударил аналогичную проблему. Мое приложение работает в отдельном домене приложения как дополнение к стороннему программному обеспечению (Outlook). Из-за различных причин мне нужно вызвать GC.Collect и GC.WaitForPendingFinalizers для полного выпуска ссылок COM (обычных процедур взаимодействия недостаточно для Office/Outlook), когда работает какая-либо другая сторонняя добавка, мой GC.WaitForPendingFinalizers висит навсегда, поэтому я подозреваю, что в этой третьей стороне есть "плохой" финализатор. У меня нет контроля над заменой/удалением этого добавления (требование клиента), поэтому я должен сам выяснить, как сделать их совместными.
Ответы
Ответ 1
Похоже, что на самом деле это всего лишь один поток на экземпляр 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(из командной строки проще всего, IMO). Вы увидите, что один финализатор домена приложения блокирует другой.
В будущем я бы не удивился, увидев один поток финализатора на ядро, а не на AppDomain, но похоже, что у вас все еще будут проблемы: (
У вас есть мое глубочайшее сочувствие (хотя это и не решение) - как только я обнаружил тупик в Oracle Blob. Мы смогли это исправить, правильно распорядившись, но я знаю, что не все работает так красиво - и это была настоящая боль, даже если вы нашли это!