关注跟踪内核的高 CPU 使用率,我以为我已经调试了一个一直困扰我的问题,即系统进程的 CPU 使用率持续达到 20-30%。请参阅我的上一篇关于它。
我设置了 Windows 性能分析器,并能够将该过程跟踪到: 我以为这与页面文件通过函数名称猜测有关,于是禁用了我的页面文件并重新启动,但 Windows 却显示有一个页面文件并抛出错误。所以我创建了一个大约 100MB - 2048MB 的小页面文件。
这似乎解决了几个星期的问题,但现在问题又出现了,尽管页面文件只有 2GB。这似乎是在系统运行一段时间后发生的。当前正常运行时间为 8 天。
如果有内核专家可以就我下一步应该尝试什么提供建议,我会很乐意这样做。
但是 Process Explorer 在系统映像下显示不同的线程。我不知道如何调和这种差异:
进程浏览器通常会显示上述内容,但有时它也可以显示调试过滤器状态...等等。
(我相信它始终是 ThreadID 56)但是几个跟踪日志似乎总是显示我们上面看到的问题。
编辑
根据 RAM 要求添加了图像。这是在全新重启后,问题不再存在。
按照建议配置的符号路径博客加速符号加载
进程探索器
水务及私人有限公司
缓存文件夹的文件大小
在系统中发现多个版本的 dbghelp.dll。当前指向系统,但不知道应该指向哪一个。
更新
在找到以下链接后僵尸进程,我发现了以下数据(截断以删除次要条目)
374 total zombie processes.
334 zombies held by explorer.exe(1768)
298 zombies of Fences.exe
9 zombies of LogonUI.exe
7 zombies of chrome.exe
10 zombies held by ctfmon.exe(4568)
2 zombies of chrome.exe
7 zombies held by dopus.exe(27672)
3 zombies of AcroRd32.exe
2 zombies held by RuntimeBroker.exe(12184)
2 zombies of WWAHost.exe
1 zombie held by SkypeHost.exe(190152)
1 zombie of SkypeApp.exe
1 zombie held by SecurityHealthService.exe(4536)
1 zombie of MsMpEng.exe
1 zombie held by svchost.exe(1988)
1 zombie of userinit.exe
这意味着 FENCES.exe 是原因,所以我更新了该程序,稍后会再次检查。还禁用了 synergy 以确保这不是原因。
更新 2
重新启动并更新隔离后,僵尸进程问题仍然存在,因此我必须卸载隔离才能解决问题。
这是栅栏的版本
以及重启后的僵尸进程列表。
16 total zombie processes.
7 zombies held by explorer.exe(9484)
5 zombies of Fences.exe
1 zombie of GoogleUpdateCore.exe
1 zombie of DropboxUpdate.exe
1 zombie held by svchost.exe(1788)
1 zombie of userinit.exe
边注
如果我们拥有能够帮助完成所有这些事情的软件 AI,那不是很酷吗?
答案1
简单的答案是:减少例行工作量。我思考意味着要么一次使用较少的虚拟地址空间,要么添加更多的 RAM。
详细信息:首先,您看到的例程MiWalkPageTablesRecursively
与页面文件没有直接关系,而是与页面表。页表是内存结构(无论页面文件配置如何,它都存在于所有 Windows 系统中)。每个进程都有一组页表,操作系统的地址空间(“内核空间”)也有一组页表。
页表由页表条目组成;进程定义的虚拟地址空间的每个页面(4K)都有一个 PTE。所谓“定义”,是指它包括进程的映射和私有提交地址空间,以及 AWE 区域(如果有);它不包括保留或空闲地址空间 - 如果您尝试读取或写入这些区域,则会引发访问冲突。
(顺便说一句:即使您没有页面文件,您不仅仍然会有页表。即使您没有页面文件,您仍然会有分页以及磁盘的页面错误。)
这里的问题可能不是固有的MiWalkPageTablesRecursively
。毕竟这个函数(或另一个名称下的等效函数)自 NT 3.1 以来一直是 Windows 的一部分。事实上,它必须做很多工作。这可能意味着它经常被调用。
在堆栈中较早的例程中可以看到这种情况的原因。(即,靠近 WPA 显示屏顶部。)看起来,MiWalkPageTablesRecursively
在这种情况下, 的调用者是 ,而 又被 调用
MiWalkPageTables
, 又被 调用, 又被 调用 , 又被 调用……这就是我们需要走的路。MiAgeWorkingSet
MiTrimOrAgeWorkingSet
MiProcessWorkingSets
Windows 系统中的每个进程都有一个称为“工作集列表”的结构。这是由于进程的页面错误而导致 RAM 中出现错误的所有物理页号的列表。该线程(“平衡集管理器”线程)每秒被唤醒一次,以对每个进程的工作集进行清理和维护。因此,它会MiProcessWorkingSets
遍历进程,依次处理每个进程的工作集。
对于系统中的每个进程,MiProcessWorkingSets
调用MiTrimOrAgeWorkingSet
。此例程名称指的是“修剪”工作集(这意味着识别长期未使用的页面并将其从进程中逐出,以便在 RAM 中为其他内容腾出空间),或“老化”工作集,这意味着增加自上次扫描以来未访问的每个工作集列表条目的“年龄”计数器,或将计数器归零(如果已访问)。(该名称指的是会计中执行的“老化”任务,通常每月或每天执行一次。)然后,“修剪”函数使用“年龄”计数器来识别最不常用的页面。
从结果为 的事实MiTrimOrAgeWorkingSet
来看MiWalkPageTablesRecursively
,我们可以推断它们正在扫描页表定义的虚拟地址空间以查找工作集中的页面。现在考虑:MiTrimOrAgeWorkingSet
处理每个进程所需的时间将大致与进程的虚拟地址空间大小成正比。每次处理所需的总时间MiProcessWorkingSets
将大致与进程数量成正比。
这件事要么正在处理一个进程工作集中的大量页面,要么必须处理很多进程。
而且...它为什么这么忙?它直到工作集老化后才会“修剪”工作集,并且“修剪”工作集的量取决于 RAM 压力 - 即 RAM 的短缺程度。
您的系统内存不足吗?请发布任务管理器的“性能”选项卡 |“内存”页面的快照,以及按“工作集”列排序的“详细信息”页面;以及资源监视器的“内存”选项卡(按“硬故障”列排序);以及 RAMmap 的使用计数页面。
另外,请发布更多您拥有的 WPA 跟踪,以显示更多调用的“深度”。或者将 .etl 文件发布到某个共享服务上,并在此处链接到它。(先将其压缩 - 压缩效果非常好。)
补充:为什么 WPA 和 Process Explorer 之间的例程名称不匹配
至于例程名称,真正的问题是“为什么 Process Explorer 中显示的例程名称完全错误。” 您的案例中有两个原因,您必须同时解决这两个问题。
第一个问题是,您似乎没有为 Process Explorer 正确配置符号。仅为 Windows Performance Analyzer 配置它们还不够。
一个明确的迹象表明您没有这个权限,那就是“系统”进程中的所有或几乎所有线程都显示一个模块名称(something.sys 或 something.exe,通常是 ntoskrnl.exe),后面跟着一个偏移量,例如+0x245
屏幕截图中的 -。看到几个这样的情况是正常的,但您应该看到一大堆 ntoskrnl!例程名称其次是不抵消。
要修复此问题,请参阅这一页来自Windows 性能分析现场指南。您需要设置 Process Explorer 的符号搜索路径 - 您可以使用为 WPA 设置的相同符号文件路径 - 并且您需要将 ProcExp 指向 Windows 调试工具附带的 DLL。因此,您需要安装调试工具 - 并不是您直接使用调试器,而是 Process Explorer 需要该 DLL。
造成差异的第二个原因是,即使您为 Process Explorer 正确设置了符号文件,它显示的例程名称通常也不会与 Performance Analyzer 识别的内层例程名称匹配。不过,您应该在堆栈开头附近的例程名称上找到匹配项(显示在 WPA 中显示的例程调用树的顶部)。
例如 - 在您的情况下,第一个感兴趣的例程是KeBalanceSetManager
。(之前的两个对于系统进程中的每个线程都是相同的,但是KeBalanceSetManager
是该线程的“顶级”例程。)正确配置符号后,Process Explorer 应向您显示一个以此为“起始地址”的线程,如下所示:
Process Explorer 无法向您显示,MiWalkPageTablesRecursively
因为这是大约六次从记录为线程起始地址的堆栈调用,并且它甚至不是当前最内层的例程(即它不在堆栈顶部)。此类信息(即使很容易获得,但事实并非如此)会变化太快,无法在 Process Explorer 显示中发挥作用,因此它不会尝试。
注意:即使符号正确,系统进程中的几个线程显示“起始地址”的情况也很常见GemCCID.sys+0xd138
,例如,正如您将在我的示例中看到的那样。所讨论的模块(GemCCID.sys)显然不是 Microsoft 提供符号文件的模块,因此 Process Explorer 只能说“线程起始地址位于此文件中代码开头的 0xd138 字节处,这就是我所知道的全部内容。”
希望这能有所帮助!如果您还有其他问题,请告诉我。