gpt4 book ai didi

.net - ServerGC 应用程序中的 GC 线程数非常高

转载 作者:行者123 更新时间:2023-12-03 12:43:49 25 4
gpt4 key购买 nike

TL;DR: 启用了 Server GC 的应用程序显示了几十个特殊的 GC 线程并超时挂起。这有什么可以解释的?

这些天我被困在 .NET 服务上发生的奇怪的多线程/争用问题上。症状如下:

  • 程序长时间挂起(秒到分钟)
  • 线程数异常高
  • 就在程序停止响应时出现争用高峰(参见下图)
  • 同一个程序部署在不同的服务器上,有些实例完全没有问题(同样的硬件/OS/CLR)

  • Peak of contention

    我立即怀疑我们代码中的一个问题会导致托管线程池随着时间的推移启动大量线程,所有线程都试图共享一个或多个公共(public)资源。看起来我们对 ThreadPool 的使用非常小且非常可控。

    我设法获得了一个尚未挂起的服务的转储文件,该服务已经有非常多的线程(超过 100,正常状态下应该是 20 左右)

    使用 windbg + sos,我们确定 ThreadPool 大小是可以的:
    0:000> !threadpool
    CPU utilization: 0%
    Worker Thread: Total: 8 Running: 1 Idle: 7 MaxLimit: 32767 MinLimit: 32
    Work Request in Queue: 0
    --------------------------------------
    Number of Timers: 1
    --------------------------------------
    Completion Port Thread:Total: 1 Free: 1 MaxFree: 64 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 32

    只有8个工作线程...然后我列出了所有托管线程堆栈,发现其中很多我无法识别。请参阅下面的一个示例:
    0:000> !eestack
    (...)
    Thread 94
    Current frame: ntdll!NtWaitForSingleObject+0xa
    Child-SP RetAddr Caller, Callee
    0000008e25b2f770 000007f8f5a210ea KERNELBASE!WaitForSingleObjectEx+0x92, calling ntdll!NtWaitForSingleObject
    0000008e25b2f810 000007f8ece549bf clr!CLREventBase::WaitEx+0x16c, calling kernel32!WaitForSingleObjectEx
    0000008e25b2f820 000007f8f5a2152c KERNELBASE!SetEvent+0xc, calling ntdll!NtSetEvent
    0000008e25b2f850 000007f8ece54977 clr!CLREventBase::WaitEx+0x103, calling clr!CLREventBase::WaitEx+0x134
    0000008e25b2f8b0 000007f8ece548f8 clr!CLREventBase::WaitEx+0x70, calling clr!CLREventBase::WaitEx+0xe4
    0000008e25b2f8e0 000007f8ed06526d clr!SVR::gc_heap::gc1+0x323, calling clr!SVR::GCStatistics::Enabled
    0000008e25b2f940 000007f8ecfbe0b3 clr!SVR::gc_heap::bgc_thread_function+0x83, calling clr!CLREventBase::Wait
    0000008e25b2f980 000007f8ecf3d5b6 clr!Thread::intermediateThreadProc+0x7d
    0000008e25b2fd00 000007f8ecf3d59f clr!Thread::intermediateThreadProc+0x66, calling clr!_chkstk
    0000008e25b2fd40 000007f8f8281832 kernel32!BaseThreadInitThunk+0x1a
    0000008e25b2fd70 000007f8f8aad609 ntdll!RtlUserThreadStart+0x1d
    (...)

    使用 !threads -special命令,我终于发现这些线程是特殊的GC线程:
    0:000> !threads -special
    ThreadCount: 81
    UnstartedThread: 0
    BackgroundThread: 49
    PendingThread: 0
    DeadThread: 21
    Hosted Runtime: no
    (...)
    OSID Special thread type
    1 804 DbgHelper
    2 f48 GC
    3 3f8 GC
    4 1380 GC
    5 af4 GC
    6 1234 GC
    7 fac GC
    8 12e4 GC
    9 17fc GC
    10 644 GC
    11 16e0 GC
    12 6cc GC
    13 9d4 GC
    14 f7c GC
    15 d5c GC
    16 d74 GC
    17 8d0 GC
    18 1574 GC
    19 8e0 GC
    20 5bc GC
    21 82c GC
    22 e4c GC
    23 129c GC
    24 e28 GC
    25 45c GC
    26 340 GC
    27 15c0 GC
    28 16d4 GC
    29 f4c GC
    30 10e8 GC
    31 1350 GC
    32 164 GC
    33 1620 GC
    34 1444 Finalizer
    35 c2c ProfilingAPIAttach
    62 50 Timer
    64 14a8 GC
    65 145c GC
    66 cdc GC
    67 af8 GC
    68 12e8 GC
    69 1398 GC
    70 e80 GC
    71 a60 GC
    72 834 GC
    73 1b0 GC
    74 2ac GC
    75 eb8 GC
    76 ec4 GC
    77 ea8 GC
    78 28 GC
    79 11d0 GC
    80 1700 GC
    81 1434 GC
    82 1510 GC
    83 9c GC
    84 c64 GC
    85 11c0 GC
    86 1714 GC
    87 1360 GC
    88 1610 GC
    89 6c4 GC
    90 cf0 GC
    91 13d0 GC
    92 1050 GC
    93 1600 GC
    94 16c4 GC
    95 1558 GC
    96 1b74 IOCompletion
    97 ce4 ThreadpoolWorker
    98 19a4 ThreadpoolWorker
    99 1a00 ThreadpoolWorker
    100 1b64 ThreadpoolWorker
    101 1b38 ThreadpoolWorker
    102 1844 ThreadpoolWorker
    103 1b90 ThreadpoolWorker
    104 1a10 ThreadpoolWorker
    105 1894 Gate

    超过 60 个“GC”线程...所以我检查了我的不同服务实例的设置,并发现有问题的那些配置了 GC Server ,而其他人则没有。

    更多信息:
  • 我们使用 .NET 4.5
  • 我们在所有机器上使用 Windows 2012 Server
  • 我们在双八核服务器上运行(2 个 CPU、16 个物理内核、32 个逻辑内核)

  • 我现在正在尝试做的事情:
  • 我正在尝试获取其他转储(当程序有更多线程时,程序何时挂起等)
  • 我会尝试禁用 GC Server设置有问题的实例,但问题可能需要一些时间才能发生。

  • 所以这是我的问题 :
  • 一个 GC 服务器配置的 .NET 程序有这么多 GC 线程是正常的吗?我认为 Server GC 每个处理器只有一个 GC 线程。
  • 这是否与我在这些服务上看到的问题有关,即随着时间的推移数百个线程,由于争用而导致大量进程卡住?
  • 最佳答案

    使用 Server GC,每个逻辑核心将有一个线程(即 affinity set 到该核心)。因此,在您的情况下,应该至少有 32 个线程。如果您打开了后台 GC,则可能会有更多的工作线程处理每个堆 (reference) 的图形。

    还要记住,这些 GC 线程将在 THREAD_PRIORITY_HIGHEST 运行。这可以很容易地饿死任何尚未被 GC ( reference ) 暂停的线程。

    现在,就您的其他线程而言,无论垃圾收集器如何,一个进程中的 500 多个线程都会产生大量争用。所以弄清楚这些线程是什么对你的调查很重要。

    看点

  • 查看Background GC是否开启,如果开启,尝试不开启运行(4.5的Server GC支持此模式)。
  • 尝试减少线程池中的最大线程数(32767 是不健康的最大值)。

  • 您也可以使用 procdump.exe在性能下降时帮助捕获小型转储。

    关于.net - ServerGC 应用程序中的 GC 线程数非常高,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18761351/

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