2023年1月

有一天,我在调试一个问题,在一个进程上弹出一个Waston对话框。让我吃惊的是,在Waston触发的堆栈上,有一个带有Testcatch(…)块的非托管C++函数。据我理解,此块应该捕获Windows中抛出的任何用户模式异常,包括来自RaiseExceptionr调用(例如,C++异常)、AV、堆栈溢出等的异常。为什么异常会逃出这样的块而变得未处理?我发现异常是调试中断。在X86中,它由操作码0xCC或“int3”触发。当我调试到VCRT的EH代码时,我发现catch(…)故意让调试中断。它确实有意义:debug break是为了停止调试器,因此源代码不应该处理它。我只是从来没有意识到。

您看到的是一个非托管异常,它在CLR中引发。它是非常通用的,用于在深入本机代码时发出错误条件的信号。名称的“消息”部分是为Microsoft测试人员设计的。只需等待这个异常变成一个托管异常。如果是良性的话就被吞下去。
或者取消选中Project+Properties,Debugging,Enable unmanaged code Debugging复选框,这样你就看不到它了。或者使用Debug+Exceptions并取消选中Win32异常的抛出复选框,这样调试器就不会在这类异常上停止。

我发现一个很棒的工具,可以很好地显示进程中的内存使用情况。

这个示例工具将为您提供虚拟内存空间的直观概述(从内存转储),显示您的分配存在于何处以及您拥有的分配类型。例如,在下面的屏幕截图中,您可以看到在内存空间的开始,我们有大量的虚拟分配(深绿色-已提交,浅绿色-保留),然后我们有大量的可用空间(白色),在内存空间的末尾,我们可以看到我们的DLL分散开来(深红色)。


在底部屏幕中,我们可以看到GC(.NET)堆。换句话说,我们在顶部屏幕上看到的大多数虚拟分配实际上是GC堆。有一点需要注意的是,对于GC堆,它不显示为GC堆保留的内容,只显示提交的内容,即我们实际使用的内容。


我把它们分开,这样你就可以在非.net应用程序中使用这个工具了。


研究这样的东西的目的是为了弄清楚我们有多少碎片,我们有多少保留内存和提交内存等等。如果我们确实有很多碎片,我们应该从哪里开始寻找以减少碎片。

原来的工具有点复杂,因为它可以读取内存转储等,并允许您放大不同的区域以获得更多的细节,但在大多数情况下,上面看到的已经足够了。

要使用示例工具,请执行以下步骤:

1、在windbg中打开内存转储并正确设置符号

2、运行!address ,然后拷贝输出到一个文本文件

3、Load sos

4、运行!eeheap –gc ,然后拷贝输出到另一个文本文件

5、打开工具,点击加载

 

在帮助客户调试问题的过程中,有些事情会反复出现,从而产生“痛点”。想到的主要问题是:线程、锁、内存、异常和性能。至少这些似乎是我参与的主要问题。
除了例外,人们常常惊讶地发现,他们的应用程序中发生了多少他们不知道的异常。然而,对于微软的异常处理指南来说,一个很好的“切入点”是处理和聚焦异常。重要的是不要使用异常来控制正常的程序流。例外情况只有在特殊情况下才会发生。如果可以在不引发异常的情况下检查特定条件,那么就这样做。抛出异常对性能不好,而且还会使调试正在生产中的应用程序变得更困难,因为它们会妨碍您的工作,并使您更难解决真正(和真正意想不到的)问题。

今天我将讨论一个简单但功能强大的GUI工具,用于本地或远程配置Windows系统进行内存转储。工具的名称是DumpConfigurator它可以从CodePlex访问。

该工具可用于当前支持的所有Windows操作系统版本。下载后,请使用管理员权限启动它以获得以下UI:

GUI是不言而喻的,所有设置都可以通过单击“保存设置”进行编辑和保存。必须重新启动系统才能使设置生效。