使用 .NET 诊断分析器调试托管内存转储
在本教程中,将:
- 打开内存转储
- 选择并对转储执行分析器
- 审阅分析器结果
- 转到有问题的代码
在本文所述的示例中,存在的问题是,你的应用没有及时响应请求。
在 Visual Studio 中打开内存转储
在 Visual Studio 中,使用“文件”>“打开”>“文件”菜单命令来打开内存转储,然后选择内存转储。
注意到,在“内存转储摘要”页上,有一个名为“运行诊断分析”的新“操作”。
选择此操作,以启动调试器,并打开新的“诊断分析”页,其中列出了按基础症状组织的可用分析器选项。
选择并对转储执行分析器
若要调查这些症状,可以在“进程响应性”下找到最佳选项,因为它与本示例中的问题最匹配。
单击“分析”按钮,以启动调查过程
分析器将根据在内存转储中捕获的进程信息和 CLR 数据的组合来显示结果。
审阅分析器结果
在此示例中,分析器发现了两个错误。 选择分析器结果来查看“分析摘要”和建议的“修正”。
“分析摘要”指明“CLR 线程池的线程极其缺乏”。 此信息表明,CLR 目前已经使用了所有可用的线程池线程;也就是说,在线程被释放之前,你的服务无法响应任何新请求。
注意
在此示例中,“修正”指明“不要同步地等待监视器、事件、任务或其他任何可能阻止线程的对象。 看看能否将方法更新为异步的。”
转到有问题的代码
下一个作业是查找有问题的代码。
在你单击“显示调用堆栈”链接后,Visual Studio 会立即切换到出现此行为的线程。
“调用堆栈”窗口会显示一些方法,这些方法可能可以快速区分我的代码 (SyncOverAsyncExmple. ) 与 Framework 代码 (System. )。
每个调用堆栈帧都对应于一个方法,在你双击堆栈帧后,Visual Studio 会转到此线程上直接导致这种情况发生的代码。
在此示例中,没有任何符号或代码,但在“未加载符号”页上,可以选择“反向编译源代码”选项。
在下面的反向编译源代码中,可以明显地看到一个异步任务 (ConsumeThreadPoolThread) 正在调用同步阻塞性函数。
注意
“DoSomething()”方法包含 WaitHandle.WaitOne 方法,此方法阻塞当前线程池线程,直到它收到信号。
为了提升应用响应性,请务必从所有异步上下文中删除阻塞性同步代码。