栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Windows调试技巧&工具

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Windows调试技巧&工具

文章目录
  • 前言
  • crash
  • anr
  • memory leak
  • dead lock
  • high cpu usage
  • Profile
  • 手工复原堆栈
    • GFlags

前言

我们使用调试工具的时候,一般是要处理以下问题:

  1. crash
  2. anr application no response
  3. memory leak
  4. dead lock
  5. high cpu usage
  6. …

Windows平台上有很多对应的处理方案,不过现有的方案一般都有一个通病:一旦打开某些调试功能或者系统设置,调试目标的性能就会成倍下降。这一点有时候会对调试来带很大的干扰,比如出现目标程序UI线程卡顿,导致无法正常操作,或者没发现要调查的问题,反而是发现了一堆性能方面的问题。

crash

崩溃的情况可以从几个正交的维度来划分:是否必现,开发的机器上是否可以复现,是否抓到crash dump。

一旦接手一个crash问题排查,可以按照下面的步骤来排查:

  1. 发现问题的机器上是否可以复现。可以复现的情况又分为:
    • 必现 : 这个情况是最简单了。
    • 高概率复现 :这个也比较简单。
    • 低概率复现,甚至只出现一次 :这个最棘手,作为开发最怕遇到这类问题。但是理论上讲,只要能发现一次就一定有一个必现的路径,只不过实践中碰到的概率低而已。套用一句话来描述就是:crash只有0次和无数次。
  2. 能复现的话,是否有复现路径。
    • 有的话,开发的机器上是否可以复现:那么直接用调试器来看就好了,这个最简单了,调试器就可以直接抓到crash点。
    • 开发的机器上不能复现的话,qa的机器上是否可以复现:可以通过远程调试的方法来处理。
    • 如果开发和测试的机器都不能复现的话,可能就需要联系客户了。这个要做好准备,这时候可以使用的方法就是:日志+dump。
      • 使用dump还要看是否能(尽量)跑debug版本,因为有时候release版本缺少一些符号信息,可能会出现即使复现了,但由于缺少符号,缺少active信息而导致无法进一步查问题。
      • 提一下,日志对于crash问题来说往往帮助不大,不过聊胜于无。
  3. 走到这一步,那就是说这个问题很可能不好复现,而且拿不到dump信息,那么这时候问题的解决就很可能没希望了。留下最后一个办法就是:耐心。排查代码,不论使用什么方法,在怀疑的点上加日志,做好准备抓dump,部署到目标环境,然后静候crash发生。

对于上面的场景,其实概括起来处理方法就三种:

  1. 本地调试:一般是使用MSVC
  2. 远程调试:MSVC或者WinDbg都可以
  3. 抓dump分析:MSVC或者WinDbg都可以,生成dump的方式,可以在资源管理器里面找到目标进程,右键执行创建转储文件;或者使用MSVC/WinDbg的创建dump功能。
anr

首先,对于anr的问题要注意的一个问题是,一定要确定anr确实发生了,因为有时候可能是程序运行环境配置较差导致的,静置一会儿看看是否就没问题了。当然如果干脆就不允许出现anr,那么应该有两方面的考虑:给出最低环境配置和找出造成anr的问题代码(比较有追求的做法)。

确定是anr问题了,那么接下来就要采取一些措施,比如动态抓dump看UI线程卡在哪里了。或者直接制造一个crash,也是得到dump,调查一下UI线程卡在哪里了。当然如果能上(本地或者远程)调试器的话是最好的了,anr的时候直接让程序停下来就可以在call stack中看到UI线程在干嘛。

另外提一下,mac上有一个不错的工具,可以在活动监视器里面采样,从而直观地看到哪行代码有问题。Windows系统上就只能用msvc工具来查了,但毕竟并不是所有(测试/客户的)环境都有调试工具,不是很好查;同时这个问题还可能与high cpu usage或者dead lock有点关联。

memory leak

内存泄露问题,可以:

  • 使用msvc的Heap Profiling工具,通过take snapshot不同时间点的内存快照,进行对比得到内存泄露的点。
  • Windows 10上可以使用UMDH工具来做类似的动作。
  • Dr. Memory,下载地址
  • Top 20+ Memory Leak Detection Tools For Java, C++ On Linux And Windows
  • 通过Application Verifier工具中的内存相关功能查看。通过WinDbg配合Application Verifier来调试是一个不错的组合,WinDBg可以及时地查看出问题时对应句柄等资源的信息。
  • 使用 Debug Diagnostic Tool,根据指定的内存阈值抓取dump,这个工具的另一个名字叫 “DebugDiag”。参考 Memory dumps to study a high-CPU performance issue,使用这个工具需要对系统的各种计数器的含义比较了解。调试诊断工具 (DebugDiag) 旨在帮助解决诸如挂起、性能下降、内存泄漏或内存碎片以及任何用户模式进程中的崩溃等问题。
  • Physical and Virtual Memory in Windows 10 介绍Windows 10上内存知识很全面的一篇文档,里面有很多精美的插图。
  • Deleaker Blog Visual Studio 20xx的一个付费插件。
  • 微软官方工具介绍的一个视频集合:Defrag Tools
  • 原本在channel9上的两个内存管理的视频:Mysteries of Memory Management Revealed Part1,Part2
  • A story of fixing a memory leak in MiniDumper 使用VMMap + WPT分析内存泄露的一个不错的例子。
  • milostosic/MTuner is a C/C++ memory profiler and memory leak finder
dead lock

发现死锁本身就是一个问题,比如非UI线程死锁,可能就没有UI线程卡死那么直观。可能是某些对该线程的同步调用卡住,或者异步调用没有结果返回才能发现。

发现之后可以抓dump,或者上调试器。

high cpu usage

Windows上由于缺少一个对进程的各个线程采样统计的工具(我没发现),所以这个问题查起来没有那么直接。WinDbg上可以用!runaway来查CPU的使用时间,但是这个使用时间,我们无法指定开始统计和结束统计的时间点,也就是说真正耗时的操作可能会被很早运行的线程运行时长超过,导致我们定位不出来。

Profile

PC Profile工具

手工复原堆栈

参考 Manually Walking a Stack

堆栈失效,可能是由于对无效地址的调用导致调试器丢失了返回地址的位置;或者您可能遇到了无法直接获取堆栈跟踪的堆栈指针;或者可能存在其他一些调试器问题。

思路是:

  • 先从检查符号开始 x *! 命令
  • dd esp/rsp 查看栈指针附近的信息,找出可能是函数指针的值,这里要注意排除掉下面的值:
    • 一般整数比较小,dd的时候大部分位是0,这类值不太可能是函数地址
    • 英文字符的范围一般在 [20,7f] 区间
    • 指向栈上的指针变量大小一般与esp/rsp接近
    • 函数指针一般不太可能重复
    • 状态码通常以 ac (c00000d6) 开头
    • 最后,栈的地址应该位于模块的区间内,也就是在第一步x命令找到的模块的地址区间内
  • 这样得到一组函数指针备选集,然后逐个使用ln address查看对应符号,得到一组可能的函数调用符号
  • 然后通过反汇编指令u 函数指针备选集合中的每一个元素的前一个地址,看看得到的结果是否匹配上面那组符号,从而构建出调用堆栈来。
GFlags

Windows上好多调试功能都需要 gflags 这个工具。

GFlags(全局标志编辑器)gflags.exe 启用和禁用高级调试、诊断和故障排除功能

gflags官方有一个实例说明:GFlags Examples

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1002097.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号