gpt4 book ai didi

.net - AppDomain 卸载卡住的原因

转载 作者:行者123 更新时间:2023-12-03 19:35:21 28 4
gpt4 key购买 nike

我仍在尝试了解持续存在的问题,但它几乎可以概括为无法卸载 AppDomain

它发生在将 ASP.NET WebAPI 部署到 Azure 应用服务期间,我们观察到以下情况:

  1. 进程 ID 不会更改,新部署托管在同一进程中(AFAIU,它是通过卸载旧 AppDomain 并使用更新的二进制文件启动新 AppDomain 来完成的)
  2. Azure PaaS 诊断在错误部分显示以下内容:

"In w3wp_12396.dmp, the HttpRuntime for the application /LM/W3SVC/1523308129/ROOT is in the middle of a shutdown."

  • 分析内存转储时,我们看到设置了 IsAbortRequested 标志的线程,但它们似乎永远不会完成(此处 WinDbg !threads 的输出: https://pastebin.com/7CXYcffy )

  • 在内存转储中,我们还看到许多具有“UNLOAD_REQUESTED”阶段的 AppDomain,它们似乎从未完成卸载(!DumpDomain 的完整输出位于此处:https://pastebin.com/kahZQuWN)

  • Domain 7:           000001c67062c800LowFrequencyHeap:   000001c67062cff8HighFrequencyHeap:  000001c67062d088StubHeap:           000001c67062d118Stage:              UNLOAD_REQUESTEDSecurityDescriptor: 000001c6705c5680Name:               /LM/W3SVC/1523308129/ROOT-6-131687140950004974
    1. No deadlocks detected (via WinDbg SOSEX plugin's !dlk command at least, which usually covers majority of deadlock cases)

    2. No code cancels Thread Abort (no Thread.ResetAbort() called)

    The only way we can fix the problem now is to kill process (stop Azure AppService).

    What are the possible reasons for AppDomain's inability to unload?

    UPDATE. In the thread stacks we got a hint that it might have something to do with our custom Azure Blob Log4net appender, and I found that when such appender is created (once per app) it spawns new thread with following structure.

    while (true)
    {
    try
    {
    Flush(); // pseudocode
    Thread.Sleep(10000);
    }
    catch(Exception)
    {
    }
    }

    不确定我理解为什么它会导致完全不可停止的线程(因为 ThreadAbortException 不会被 catch 停止),但看起来像是将 while (true) 更改为 while (!Environment.HasShutdownStarted && !_stopping) 解决了问题(调用 Appender OnClose 时设置 _stopping ,这对 log4net 来说是一种优雅的关闭)...

    最佳答案

    这似乎是一个 JIT 错误。是的,JIT 中的错误!我发现那里记录了几乎相同的故事:http://labs.criteo.com/2017/04/ryujit-never-ending-threadabortexception/ .

    为了演示该问题,您可以运行以下代码。仅适用于 Release模式,仅适用于 x64 平台(并且我的目标是 .NET 4.5.2)。

    除非您手动重新抛出异常,否则您将观察到记录的异常链。为什么这是 CLR/JIT 中的错误?因为 CLR/JIT 负责在设置线程的 AbortRequested 标志时在“安全位置”注入(inject) throw ThreadAbortException

    引用 Jeffrey Richter 的“CLR via C#”(以下代码违反了规定):

    Even when code catches the ThreadAbortException, the CLR doesn’t allow the exception to be swallowed. In other words, at the end of the catch block, the CLR automatically rethrows the ThreadAbortException exception.

    还有 GitHub 中的错误:https://github.com/dotnet/coreclr/issues/16122 .

    static void Main(string[] args)
    {
    var mutex = new ManualResetEventSlim();

    var t = new Thread(() =>
    {
    while (true)
    {
    try
    {
    if (!mutex.IsSet)
    {
    mutex.Set();
    }

    // Do some stuff

    Thread.Sleep(100);
    }
    catch (Exception ex)
    {
    Console.WriteLine("Exception: " + ex.Message);

    // the lines below FIX the issue
    //if (ex is ThreadAbortException)
    // throw;
    }

    // FIXES the issue as well
    //Thread.Sleep(0);
    }
    });

    t.Start();

    // Wait for the thread to start
    mutex.Wait();

    t.Abort();

    Console.ReadLine();
    }

    关于.net - AppDomain 卸载卡住的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50028901/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com