0

我正在运行 .NET 4.8 x64 (4.8.4300.0),在 ca 之后。14h压力测试GC时间比开始时高很多。使用 PerfView 我可以看到 Gen0 Heap 的大小增长了很多。Gen0 堆大小和 .NET 4.8 是否存在已知问题?

迭代 10 在此处输入图像描述 在此处输入图像描述

  • 总 CPU 时间:136,245 毫秒
  • 总 GC CPU 时间:7,171 毫秒
  • 总分配数:10,023.772 MB
  • GC CPU MSec/MB 分配:0.715 MSec/MB
  • GC 暂停总时间:8,361.5 毫秒
  • 垃圾收集暂停时间百分比:5.5%
  • 垃圾收集所花费的 CPU 时间百分比:5.3%
  • 最大 GC 堆大小:460.052 MB
  • 峰值进程工作集:1,166.688 MB
  • 峰值虚拟内存使用量:7,314.285 MB

迭代 300 在此处输入图像描述 在此处输入图像描述

  • 总 CPU 时间:141,466 毫秒
  • 总 GC CPU 时间:14,364 毫秒
  • 总分配:10,235.755 MB
  • GC CPU MSec/MB 分配:1.403 MSec/MB
  • GC 暂停总时间:22,767.4 毫秒
  • 垃圾收集暂停时间百分比:13.6%
  • 垃圾收集所花费的 CPU 时间百分比:10.2%
  • 最大 GC 堆大小:887.517 MB
  • 峰值进程工作集:1,916.793 MB
  • 峰值虚拟内存使用量:8,047.583 MB

当我从 ETW 绘制各种迭代计数的 GC、后台 GC 和诱导 GC 的 CPU 消耗时,我发现与增加的 GC 成本和迭代计数有明显的相关性。 在此处输入图像描述

奇怪的是托管堆并没有真正变得更大。这看起来不像是托管内存泄漏(好吧,它泄漏了一点,但没有那么多),而是一些 GC 问题,还是我以错误的方式查看数据?

更新 1 这是 GC 的调用堆栈,似乎相当昂贵:

Stack Tag, Stack, Weight (in view) (ms)
4, ,   Background GC, , 245.131400
5, , , [Root], 245.131400
6, , ,   ntdll.dll!RtlUserThreadStart, 245.131400
7, , ,   kernel32.dll!BaseThreadInitThunk, 245.131400
8, , ,   clr.dll!Thread::intermediateThreadProc, 245.131400
9, , ,   clr.dll!<lambda_29e7ea55b6ca6bda8a02df3a0a3e58b1>::operator(), 245.131400
10, , ,   clr.dll!WKS::gc_heap::bgc_thread_function, 245.131400
11, , ,   clr.dll!WKS::gc_heap::gc1, 245.131400
12, , ,   clr.dll!WKS::gc_heap::background_mark_phase, 245.131400
13, , ,   |- clr.dll!GCScan::GcScanHandles, 203.131000
14, , ,   |    clr.dll!Ref_TraceNormalRoots, 203.131000
15, , ,   |    clr.dll!HndScanHandlesForGC, 203.131000
16, , ,   |    clr.dll!TableScanHandles, 203.131000
17, , ,   |    clr.dll!BlockScanBlocksWithoutUserData, 203.131000
18, , ,   |    clr.dll!ScanConsecutiveHandlesWithoutUserData, 203.131000
19, , ,   |    |- clr.dll!PromoteRefCounted, 202.131100
20, , ,   |    |    |- clr.dll!WKS::gc_heap::background_promote, 196.131800
21, , ,   |    |    |    clr.dll!WKS::gc_heap::background_mark_simple, 196.131800
22, , ,   |    |    |    clr.dll!WKS::gc_heap::background_mark_simple1, 196.131800
23, , ,   |    |    |    |- clr.dll!WKS::gc_heap::background_mark_simple1<itself>, 186.138400

不确定哪些对象可以使成本如此昂贵。但它看起来CPU占主导地位。这是一个 Gen2 GC,它确实需要超过 250 毫秒才能完成

Induced Gen2 GCs 似乎来自背景 GC 在此处输入图像描述

4

1 回答 1

1

进行转储后,我发现了许多 RefCounted 对象,即MS.Internal.Automation.ValueProviderWrapper,它们通过 UI 自动化使许多 UI 对象保持活动状态。我认为引用计数有效,这意味着驱动 UI 的另一个进程正在泄漏 UI 自动化对象。至少现在可以解释增加的 GC 成本。

MemAnalyzer 也有很大帮助:https ://github.com/Alois-xx/MemAnalyzer

一定要看看正确的事情。由于其堆栈采样方法,PerfView 在计算对象方面非常糟糕。使用 Memanalyzer,您可以收集准确的数字和差异。

C:\dumps>for %i in (*.dmp) do memanalyzer -f MemoryDump_5.dmp -f2 %i -o Diff_5_%i.csv

在此处输入图像描述

如果我随后添加一个格式为 = ObjectDiff/IterationDiff 的列,我可以计算不同转储每次迭代的泄漏率。如果我们每次迭代泄漏一个对象,我只需要搜索大约 1 个或多个对象以查找与每次迭代相关的泄漏,这使得推理根本原因变得更加容易。

在此处输入图像描述

于 2021-07-23T10:05:30.020 回答