Windbg 分析 Dump File 简单演示(转)

WinDebug 调试工具-0 Loading Dump File [F:\Debug分析调试工具\SysinternalsSuite\ProDebug.exe_180712_171559.dmp] User Mini Dump File with Full Memory: Only application data is available Comment: ' *** procdump64.exe  -ma -t 9872 ... 阅读详情

From:http://www.rainsts.net/article.asp?id=765

使用 Windbg 调试 Dump 文件是一种常用的手法,不同于 Attach Process,这种方式允许我们 "离线" 完成调试工作。Dump 文件保存了目标进程某个时间点的内存及相关程序信息镜像。本文只是一个简单的调试过程演示,更多细节可参考 Windbg 及 SOS.dll 的相关帮助。

class Program
{
  private List<Byte[]> list = new List<byte[]>();

  void Test1()
  {
    for (int i = 0; i < 10; i++)
    {
      list.Add(new byte[1024 * 1024 * 10]);
    }
  }

  void Test2()
  {
    new Thread(() =>
    {
      while (true)
      {
      }
    }).Start();
  }

  static void Main(string[] args)
  {
    var o = new Program();
    o.Test1();
    o.Test2();

    Console.WriteLine("Press any key to exit...");
    Console.ReadKey(true);
    Environment.Exit(0);
  }
}


这个测试样本会造成 CPU 及内存占用过大,这也是我们日常调试工作中最常见的两个问题。

1. 抓取 Dump 文件

我们可以直接使用 Windbg 自带的 ADPlus.vbs 完成该工作。

C:\...\Windbg> adplus.vbs -hang -o z:\temp -p 6876

Attaching the debugger to: LEARN.CUI.EXE
 (Process ID: 6876)


参数说明:

  • -hang: 表示附加到目标进程,抓取 dump 镜像,然后解除。对应的参数是 -crash 崩溃模式,该参数会终止目标进程。
  • -o: 指定 Dump 文件保存路径。
  • -p: 指定目标进程 PID。

2. 使用 Windbg 调试 Dump 文件

(1) 启动 Windbg 打开 Dump 文件 (File -> Open Crash Dump...)。

Microsoft (R) Windows Debugger Version 6.9.0003.113 X86
Copyright (c) Microsoft Corporation. All rights reserved.

Loading Dump File [Z:\Temp\...\PID-6876__LEARN.CUI.EXE__full_1e84_2008-12-19_13-01-28-781_1adc.dmp]
User Mini Dump File with Full Memory: Only application data is available

...

Executable search path is:
Windows XP Version 2600 (Service Pack 3) MP (2 procs) Free x86 compatible
Product: WinNt, suite: SingleUserTS
Debug session time: Fri Dec 19 13:01:28.000 2008 (GMT+8)
System Uptime: 0 days 1:31:57.003
Process Uptime: 0 days 0:00:21.000

......................

This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(1adc.1aa4): Wake debugger - code 80000007 (first/second chance not available)
eax=00000014 ebx=00000000 ecx=79153810 edx=7c92e4f4 esi=0012f274 edi=00000000
eip=7c92e4f4 esp=0012f228 ebp=0012f248 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCallRet:
7c92e4f4 c3 ret


(2) 载入 SOS.dll

0:000> .load sos


(3) 对于 CPU 占用过高的问题,别忘了 ThreadPool 也可能是造成问题的根源。

0:000> !threadpool

CPU utilization 0%
Worker Thread: Total: 0 Running: 0 Idle: 0 MaxLimit: 0 MinLimit: 0
Work Request in Queue: 0
--------------------------------------
Number of Timers: 0
--------------------------------------
Completion Port Thread:Total: 0 Free: 0 MaxFree: 0 CurrentLimit: 0 MaxLimit: 1000 MinLimit: 0


"CPU utilization 0%",看来这次并不是 ThreadPool 的问题。

(4) 我们看看是哪个线程占用 CPU 时间过多。

0:000> !runaway

 User Mode Time
 Thread Time
 3:1a1c 0 days 0:00:20.984
 2:1a30 0 days 0:00:00.000
 1:1a14 0 days 0:00:00.000
 0:1aa4 0 days 0:00:00.000


看来这个 Thread 3 就是我们的目标了。

(5) 切换到该线程,查看调用堆栈。

0:000> ~3 s

eax=00993034 ebx=012d4e98 ecx=012d2f18 edx=012d2f18 esi=012d2f18 edi=00000000
eip=00cd0285 esp=0115f8b4 ebp=0115f8b8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00cd0285 90 nop

0:003> !clrstack

OS Thread Id: 0x1a1c (3)
ESP EIP
0115f8b4 00cd0285 Learn.CUI.Program.<Test2>b__0()
0115f8c0 792d6cf6 System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
0115f8cc 792e019f System.Threading.ExecutionContext.Run(...)
0115f8e4 792d6c74 System.Threading.ThreadHelper.ThreadStart()
0115fb0c 79e71b4c [GCFrame: 0115fb0c]


(6) 看看这个 "Learn.CUI.Program.<Test2>b__0()" 的 IL 代码。

0:003> !name2ee * Learn.CUI.Program

Module: 790c1000 (mscorlib.dll)
--------------------------------------
Module: 00992c5c (Learn.CUI.exe)
Token: 0x02000002
MethodTable: 0099304c
EEClass: 00991320
Name: Learn.CUI.Program

0:003> !dumpmt -md 0099304c

EEClass: 00991320
Module: 00992c5c
Name: Learn.CUI.Program
mdToken: 02000002 (D:\...\Learn.CUI.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 9
--------------------------------------
MethodDesc Table
 Entry MethodDesc JIT Name
79286a70 79104934 PreJIT System.Object.ToString()
79286a90 7910493c PreJIT System.Object.Equals(System.Object)
79286b00 7910496c PreJIT System.Object.GetHashCode()
792f72f0 79104990 PreJIT System.Object.Finalize()
00cd00f8 0099302c JIT Learn.CUI.Program..ctor()
00cd0150 00993008 JIT Learn.CUI.Program.Test1()
00cd01d8 00993014 JIT Learn.CUI.Program.Test2()
00cd0070 00993020 JIT Learn.CUI.Program.Main(System.String[])
00cd0268 00993034 JIT Learn.CUI.Program.<Test2>b__0()

0:003> !dumpmd 00993034

Method Name: Learn.CUI.Program.<Test2>b__0()
Class: 00991320
MethodTable: 0099304c
mdToken: 06000005
Module: 00992c5c
IsJitted: yes
CodeAddr: 00cd0268

0:003> !dumpil 00993034

ilAddr = 00402088
IL_0000: nop
IL_0001: br.s IL_0005
IL_0003: nop
IL_0004: nop
IL_0005: ldc.i4.1
IL_0006: stloc.0
IL_0007: br.s IL_0103


有点问题,IL 并不完整。这通常是匿名方法造成的。没关系,继续。

(6) 我们将 Module 导出,然后用 Reflector.exe 查看源码。

0:003> !dumpdomain

Domain 1: 001647b0
LowFrequencyHeap: 001647d4
HighFrequencyHeap: 00164820
StubHeap: 0016486c
Stage: OPEN
SecurityDescriptor: 001532a0
Name: Learn.CUI.exe

Assembly: 00171418 [C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader: 00171488
SecurityDescriptor: 0015d288
 Module Name
790c1000 C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly: 0017a788 [D:\...\Learn.CUI.exe]
ClassLoader: 0017a7f8
SecurityDescriptor: 00172458
 Module Name
00992c5c D:\...\Learn.CUI.exe

0:003> !SaveModule 00992c5c z:\temp\a.dll

3 sections in file
section 0 - VA=2000, VASize=af4, FileAddr=200, FileSize=c00
section 1 - VA=4000, VASize=5c0, FileAddr=e00, FileSize=600
section 2 - VA=6000, VASize=c, FileAddr=1400, FileSize=200


用 Reflector.exe 打开 a.dll,我们查看 Learn.CUI.Program.<Test2>b__0() 方法的反编译结果。

[CompilerGenerated]
private static void <Test2>b__0()
{
  while (true)
  {
  }
}


很显然这就是问题之所在。

(7) 接下来,我们需要找出吃内存的大户。

0:003> !eeheap -gc

Number of GC Heaps: 1
generation 0 starts at 0x012d2e8c
generation 1 starts at 0x012d2e80
generation 2 starts at 0x012d1000

ephemeral segment allocation context: none
 segment begin allocated size
012d0000 012d1000 012d8e98 0x00007e98(32408)

Large object heap starts at 0x022d1000
 segment begin allocated size
022d0000 022d1000 02cd3260 0x00a02260(10494560)
032d0000 032d1000 03cd1010 0x00a00010(10485776)
042d0000 042d1000 04cd1020 0x00a00020(10485792)
052d0000 052d1000 05cd1020 0x00a00020(10485792)
062d0000 062d1000 06cd1020 0x00a00020(10485792)
072d0000 072d1000 07cd1020 0x00a00020(10485792)
082d0000 082d1000 08cd1020 0x00a00020(10485792)
092d0000 092d1000 09cd1020 0x00a00020(10485792)
0a760000 0a761000 0b161020 0x00a00020(10485792)
0b760000 0b761000 0c161020 0x00a00020(10485792)
Total Size 0x640a208(104899080)

------------------------------

GC Heap Size 0x640a208(104899080)


好家伙,LOH 上有一堆大户在打麻将。

(8) 查证这些大户的身份。

0:003> !dumpheap -min 85000 -stat

total 10 objects
Statistics:
 MT Count TotalSize Class Name
7933335c 10 104857760 System.Byte[]
Total 10 objects


"System.Byte[]",嗯,继续。

(9) 找出大户的具体内存地址。

0:003> !dumpheap -type Byte[] -min 85000

 Address MT Size
022d3250 7933335c 10485776
032d1000 7933335c 10485776
042d1000 7933335c 10485776
052d1000 7933335c 10485776
062d1000 7933335c 10485776
072d1000 7933335c 10485776
082d1000 7933335c 10485776
092d1000 7933335c 10485776
0a761000 7933335c 10485776
0b761000 7933335c 10485776

total 10 objects


(10) 挑一个出来,看看谁持有该大户的引用。

0:003> !gcroot 022d3250

Scan Thread 0 OSTHread 1aa4
ESP:12f468:Root:012d2e2c(Learn.CUI.Program)->
012d2e38(System.Collections.Generic.List`1[[System.Byte[], mscorlib]])->
012d2ec8(System.Byte[][])->
022d3250(System.Byte[])

Scan Thread 2 OSTHread 1a30
Scan Thread 3 OSTHread 1a1c


嘿嘿,Program 类型里面有个类型为 "List<Byte[]>" 的家伙拿了该大户的把柄。继续看看 Program 对象的信息。

0:003> !do 012d2e2c

Name: Learn.CUI.Program
MethodTable: 0099304c
EEClass: 00991320
Size: 12(0xc) bytes

Fields:
 MT Field Offset Type VT Attr Value Name
00000000 4000001 4 0 instance 012d2e38 list
79317cc4 4000002 4 ...ading.ThreadStart 0 static 012d2f18 CS$<>9__CachedAnonymousMethodDelegate1


很显然,问题就是这个 list 字段。

(11) 剩下来的工作,就是在 Reflector.exe 中查看我们前面 SaveModule 出来的那个 a.dll 源代码了。利用 Byte[] 和 list 搜索就无需我演示了吧。

private void Test1()
{
  for (int i = 0; i < 10; i++)
  {
    this.list.Add(new byte[0xa00000]);
  }
}


--------------

 

补充。。。

之前在服务器上安装了windbg,在cpu高点时运行adplus.vbs -hang -pn w3wp.exe -o d:\ops\以产生dump文件,
如果没有条件的朋友,可以使用系统自带的ntsd来产生,如
ntsd -pv -pn w3wp.exe -logo d:\out.txt -lines -c ".dump /ma d:\testlocal.dmp;q"

 

使用windbg分析dump文件的方法 https://zhuanlan.zhihu.com/p/613434365一般操作如下: 阅读详情

相关推荐

Windbg分析dump崩溃

首先抓dump.在任务管理器->进程里面进行抓dump. 然后需要的原材料有dump、源码、pdb 打开windbg把源码路径和pdb路径添加进去。 需要打开的窗口包括线程窗口(Processes and Threads)、Calls窗口、Command窗口。 把dump拖进去,如果Dump文件是64位的,在分析时,需要根据被转储文件的位数来判断是否转为32位的,转换的命令如下: ....

Scarlett_OHara的博客 3118

记一次 .NET 某旅行社审批系统 崩溃分析

这次崩溃事故主要还是第三方的SDK代码不健壮导致的死递归拖累程序崩溃,解决办法很简单,升级升级再升级,如果还有问题建议提交官方或者使用其他替代品,如果官方解决问题不活跃,你还敢用吗?

一线码农的专栏 1192

WinDbg调试dump文件

最近开始学习用WinDbg调试Dump文件,本文只是

JamesWang's study notes 1527

利用windbg简单调试dump文件

1. dump文件生成 利用下面程序(debug x86编译,release模式下需修改工程部分配置以生成pdb信息),模拟程序崩溃。 #include <windows.h> #include <dbghelp.h> #include <iostream> using namespace std; static LONG WINAPI CretateDmpFile(struct _EXCEPTION_POINTERS* pExPointInfo) { char

www_dong的博客 4856

WinDbg下载后如何抓取Dump文件?完整示例演示

掌握WinDbg下载后抓取Dump文件的完整流程,通过实际操作演示快速定位程序崩溃问题,提升调试效率,是开发者排查系统级故障的必备技能。

weixin_36296444的博客 653

使用Windbg分析dump文件的一般步骤及要点详解

通过一个问题实例详细讲解使用Windbg静态分析dump文件的完整过程。

dvlinker的技术专栏 4万+

WinDbg Preview分析用户态Dump:实战场景详细说明

通过实际案例深入讲解如何使用WinDbg Preview进行用户态Dump分析,掌握调试技巧和问题定位方法,提升对windbg preview在故障排查中的应用能力。

weixin_29717341的博客 1016

Apple 网页 SRP 登录系列文章(二):网页参数提取与会话初始化

本文深入解析了Apple网页SRP登录的第一个关键环节。文章首先指出Apple登录页面采用多层安全架构,包括跨域跳转机制和动态参数生成。重点介绍了四种关键参数(ServiceKey、SCNT、FrameId、ServiceNum)的提取技术,通过正则表达式和JSON路径解析从HTML脚本和HTTP头中获取。最后详细说明了会话初始化流程,包括访问初始页面和构建认证URL。这些技术细节揭示了Apple如何通过复杂机制确保登录过程的安全性。

Sayid_Des的专栏 1131

Windbg 分析 Dump File 简单演示

<br />预备:<br />Windbug包,可以到微软的网站上去找关键字:Debugging Tools for Windows (x86)<br /> <br />使用 Windbg 调试 Dump 文件是一种常用的手法,不同于 Attach Process,这种方式允许我们 "离线" 完成调试工作。Dump 文件保存了目标进程某个时间点的内存及相关程序信息镜像。本文只是一个简单的调试过程演示,更多细节可参考 Windbg 及 SOS.dll 的相关帮助。<br />class Program {

figerDeng的专栏 2346

ROS四旋翼无人机快速上手指南(3):工作环境文件框架与各功能包整体讲解

这一章节主要讲解无人机平台的控制文件架构和各个功能包组成和用法。

The Road of Engineer 2406

国内网络环境下Leaflet加载OpenStreetMap地图的5种替代方案(附可用瓦片地址)

本文针对国内网络环境下Leaflet加载OpenStreetMap地图的常见问题,提供了5种可用的瓦片替代方案,包括OpenStreetMap.fr HOT、OpenStreetMap.de、CartoDB、Stamen和Thunderforest,并附上详细的代码示例和选择建议,帮助开发者解决地图加载问题。

qsc901234的博客 1696

Windows下dump文件生成与分析

一、生成Dump文件方式 1.1任务管理器 在程序崩溃后,先不关闭程序,在任务管理器中找到该程序对应的进程。右键—>创建转储文件。 此时会在默认的目录下创建出一个dump文件。 可以看出,此种方法只适用于程序崩溃但没有立即自行退出的情况。倘若程序故障后自行退出,则此方法就难以应用。不过,我们可以在注册表中添加如下信息已确保系统在程序崩

icandoit2010的专栏 10万+

【系列05】端侧AI:构建与部署高效的本地化AI模型 第4章:模型量化(Quantization)

量化的基本思想是减少模型中用于表示参数和激活值的比特数。在模型训练时,参数通常使用32位浮点数(FP32)进行存储,这提供了高精度,但也消耗大量的内存和计算资源。量化则将这些32位浮点数转换成低比特数表示,通常是8位整数(INT8)。量化的原理可以概括为:对浮点数范围进行校准,并将其映射到更小的整数范围内。例如,将一个FP32的权重(如-1.5到1.5)映射到INT8的范围(-128到127)。在推理过程中,模型将使用这些低精度的整数进行计算,从而大大减少了所需的计算量。量化带来的主要收益减少模型大小。

学习,输出==》再学习再输出 1216

Dump文件的生成以及使用WinDbg静态分析

本文章主要介绍了如何生成Dump文件,包括两种方式,通过代码生成和通过注册表生成。并且介绍了WinDbg工具的下载和使用,以及如何使用WinDbg工具去静态分析Dump文件,从而找到程序的崩溃位置。

new9232的博客 1589

YOLOv8改进 | 主干篇 | 利用MobileNetV2替换Backbone(轻量化网络结构)

本文给大家带来的改进机制是,其是专为移动和嵌入式视觉应用设计的轻量化网络结构。这些模型基于简化的架构,并利用深度可分离卷积构建轻量级深度神经网络,其引入了两个简单的全局超参数,用于在延迟和准确性之间进行有效的权衡。实验表明,MobileNets在资源和准确性的权衡方面表现出色,并在多种应用(如对象检测、细粒度分类、面部属性识别和大规模地理定位)中展现了其有效性,这个模型非常适合轻量化的读者来使用。适用检测目标:轻量化网络结构适合轻量化的读者⭐⭐⭐⭐。

Snu77的博客 5686

【深度学习驱动流体力学】OpenFOAM目录流体力学求解器汇总介绍

下面这些目录结构和其中的求解器和工具展示了OpenFOAM作为一个功能强大且广泛应用的开源CFD软件框架的多样性和灵活性。每个求解器都专门用于解决不同类型的流体动力学问题,从基础的流动模拟到复杂的多相流动和燃烧模拟等各种应用场景。

源代码杀手的博客 1186

vs windbg dump分析应用程序崩溃

Windows下dump文件生成与分析 一、    生成Dump文件方式 1.1任务管理器 在程序崩溃后,先不关闭程序,在任务管理器中找到该程序对应的进程。右键—&gt;创建转储文件。   此时会在默认的目录下创建出一个dump文件。   可以看出,此种方法只适用于程序崩溃但没有立即自行退出的情况。倘若程序故障后自行退出,则此方法就难以应用。不过,我们可以在注册表中添加如下信...

PeterCuiy 1336

GD32F130之USART多机通信

简介 在多机通信中,一个从机应该只接收它需要接收的数据,且只应该在它需要接收数据时才检测串口。而始终接收RX线上的数据对从机来说是一种负担。 多机通信硬件设计 远距离方案:RS485 板级方案: 静默模式 静默模式有什么作用? 答:如果 USART 处于静默模式,所有的接收状态标志位将不会被置位。 如何进入静默模式? 答:软件可以通过将 USART_CMD 寄存器中MMCMD 位置 1 使 USART 进入静默模式。 如何从静默模式中唤醒? 答:有两种方式可选,①检测到总线

luliplus的博客 301

dump系列(1)Windows下dump文件生成与分析

Windows下dump文件生成与分析 一、生成Dump文件方式 1.1任务管理器 在程序崩溃后,先不关闭程序,在任务管理器中找到该程序对应的进程。右键—>创建转储文件。 此时会在默认的目录下创建出一个dump文件。 可以看出,此种方法只适用于程序崩溃但没有立即自行退出的情况。倘若程序故障后自行退出,则此方法就难以应用。不过,我们可以在注册表中添加如下信...

$firecat利白的代码足迹$ 1万+

北斗导航 | 基于LSTM-KF融合的北斗卫星定位算法研究框架

针对北斗卫星导航系统在复杂环境下存在的多路径效应、非视距传播等问题,提出一种基于长短期记忆网络(LSTM)与卡尔曼滤波(KF)的组合定位算法。通过LSTM网络建模定位误差的非线性特征,结合卡尔曼滤波实现动态噪声抑制,构建"粗定位-LSTM校正-卡尔曼滤波优化"的三级处理架构。实验表明,融合算法较传统方法定位精度提升42.7%,均方根误差降低至1.2米。

尘世冰封的专栏 922

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

上一篇: 使用WinDbg分析.dump文件找出CPU占用与内存占用的问题根源(转)
下一篇: 分享.net常见的内存泄露及解决方法(转)
aqbeyond
博客等级 码龄22年 13粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值