[WinDBG 技巧] 列举所有Handle(句柄)以及查看Handle 信息

本文介绍了使用WinDBG的!handle命令调试句柄的方法。通过该命令可以查看进程内所有句柄的类型和值,以及统计信息。同时,也可以查看特定句柄的详细信息。
WinDBG的 !handle 命令可以让你方便调试句柄(handle)。
查看进程内所有句柄, 输入命令行
0:014> !handle
Handle 4
  Type          Directory
Handle 8
  Type          Process
Handle c
  Type          Key
Handle 10
  Type          Mutant
Handle 14
  Type          ALPC Port
Handle 18
  Type          Key
Handle 1c
  Type          Event
Handle 20
  Type          Key
 ... (省略)
Handle 7e0
  Type          Mutant
392 Handles
Type            Count
None            17
Event           134
Section         47
File            35
Directory       3
Mutant          34
WindowStation   2
Semaphore       24
Key             47
Token           1
Process         3
Thread          27
Desktop         1
IoCompletion    4
Timer           5
Job             1
KeyedEvent      1
TpWorkerFactory 6

从WinDBG输出结果我们可以看到所有句柄的类型和值,以及统计信息(一共392个handle,其中有35个文件句柄,47个注册表句柄 .... )。
如果想查看某个句柄的详细信息, 可以用命令:
0:014> !handle 0x5c8 f
Handle 5c8
  Type          Key
  Attributes    0
  GrantedAccess 0x20019:
         ReadControl
         QueryValue,EnumSubKey,Notify
  HandleCount   2
  PointerCount  3
  Name          \REGISTRY\USER\S-1-5-21-2127521184-1604012920-1887927527-2966534\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts
  Object Specific Information
    Key last write time:  16:52:14. 5/20/2009
    Key name FileExts
0x5c8 是句柄的值, 参数f 表示显示全部信息。 我们可以看到句柄0x5c8 是注册表句柄,路径为\REGISTRY\USER\S-1-5-21-2127521184-1604012920-1887927527-2966534\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts。
值得一提的是,WinDBG 还提供了!htrace 命令,可以很方便来用检查句柄泄露(Handle Leak), 下次再写篇blog 专门介绍 !htrace 。

 
<think>我们被要求使用WinDbg中的!handle命令来排查CloseHandle调用缓慢的问题。根据引用[1]中提到,WinDbg的!handle命令可以列出当前进程的所有句柄,这有助于我们分析句柄的状态。在CloseHandle调用缓慢的场景中,我们主要关注两个方面:1.句柄的引用计数:如果句柄被多次复制(例如通过DuplicateHandle),那么CloseHandle需要等待所有引用都被关闭才会真正释放内核对象。2.句柄关联的未完成I/O操作:例如文件或套接字句柄,如果有未完成的异步I/O,CloseHandle会等待这些操作完成(或可取消的情况下被取消)才会返回。使用WinDbg的!handle命令可以查看句柄的详细信息,包括其引用计数和对象类型。以下是具体步骤:步骤1:附加到目标进程在WinDbg中,通过File>AttachtoProcess附加到出现CloseHandle缓慢的进程。步骤2:使用!handle命令查看所有句柄的摘要输入命令:!handle00这个命令会列出当前进程的所有句柄,包括句柄值、类型和对象地址。步骤3:找到导致问题的句柄根据步骤2的输出,我们可以关注那些数量异常多的对象类型(比如文件、事件、线程等),或者根据程序逻辑找到可能被频繁操作的对象。步骤4:查看特定句柄的详细信息如果我们怀疑某个句柄(例如句柄值为0x1c)有问题,可以输入:!handle0x1cf这里的'f'表示显示详细信息。在详细信息中,我们可以查看:-对象类型(如File,Event,Thread等)-引用计数(ReferenceCount)-对于文件对象,可能还会显示当前未完成的I/O数量(如果有的话)步骤5:分析引用计数高的原因如果发现某个句柄的引用计数很高(比如远大于1),说明可能有其他线程或进程(通过DuplicateHandle)还在使用这个对象。我们需要检查代码中是否有地方复制了句柄但没有关闭。步骤6:检查未完成的I/O对于文件、管道、套接字等句柄,如果CloseHandle卡住,很可能是由于未完成的I/O操作。在!handle的详细输出中,不一定直接显示未完成I/O的数量,但我们可以通过以下方法:-使用!objref命令查看对象引用链(但需要先获取对象地址)-使用!irp命令查看挂起的IRP(需要知道驱动相关知识)另一种思路:使用ProcessExplorer工具(来自Sysinternals)可以更直观地看到每个句柄的引用计数和未完成I/O数量。步骤7:结合其他命令如果怀疑是未完成I/O导致的,我们还可以使用:!thread#查看当前线程的状态,看是否在等待某个I/O操作!iochain#查看与线程关联的I/O请求包(IRP)链但是,需要注意的是,CloseHandle的调用线程在等待未完成I/O时,通常会处于等待状态(WaitReason可能是Executive或WrQueue等)。步骤8:使用WPA(WindowsPerformanceAnalyzer)进行更深入的分析引用[3]中提到使用xperf进行性能跟踪,我们可以捕获CloseHandle调用期间的内核事件,分析阻塞点。示例:使用WPA分析CloseHandle的堆栈,看是否有长时间的等待。总结:在WinDbg中,通过!handle命令我们可以:-列出所有句柄,找出可疑句柄(数量多、类型关键)-查看特定句柄的详细信息,特别是引用计数-结合其他命令(如!thread)分析线程状态但是,对于未完成I/O,!handle命令提供的信息有限,需要结合其他工具和方法。引用[1]中提到WinDbg的!handle命令,以及任务管理器查看句柄数量,这些都可以作为辅助手段。另外,引用[2]中的示例代码展示了一个可能导致CloseHandle阻塞的场景:主线程等待一个长时间运行的线程(Sleep一小时)。在这种情况下,CloseHandle(hThread)在WaitForSingleObject返回后立即被调用,所以实际上不会阻塞,因为线程已经结束。但如果我们修改代码,不等待线程结束就直接CloseHandle,那么CloseHandle会立即返回(因为线程句柄的关闭不会影响线程执行)。然而,如果线程句柄被用于其他未完成操作(比如等待线程结束),则WaitForSingleObject会阻塞,而不是CloseHandle。因此,在实际调试中,我们需要根据具体情况分析。下面是一个使用!handle命令的示例:假设我们有一个进程,句柄0x1c是一个文件句柄,我们怀疑它导致CloseHandle缓慢:0:001>!handle0x1cfHandle1cTypeFileAttributes0GrantedAccess0x120089:ReadControl,SynchRead/List,ReadEA,ReadAttrHandleCount2PointerCount3Name\Device\HarddiskVolume2\test.txt这里HandleCount=2表示有两个句柄指向同一个对象(可能是当前进程或其他进程通过DuplicateHandle复制了句柄),PointerCount=3表示内核对象的总引用计数为3(包括内核模式引用)。如果PointerCount大于1,说明还有别的引用存在,CloseHandle调用后,该进程的句柄会被关闭,但对象不会销毁,因此CloseHandle不会阻塞。但是,如果这个文件句柄有未完成的异步I/O,那么CloseHandle会等待I/O完成,即使引用计数为1。因此,要排查未完成I/O,我们可能需要更深入的工具,如WPA或使用驱动调试。对于未完成I/O,我们可以尝试使用以下命令:!fileobj<对象地址>注意:!fileobj是WinDbg的一个扩展命令,需要安装Windows调试工具包,并且需要符号支持。它能够显示文件对象的详细信息,包括当前挂起的IRP。示例:首先通过!handle获取文件对象的地址(在输出中,Handle信息里通常会包含对象地址,如Object:xxxxxxxx)然后执行:!fileobjxxxxxxxx在输出中,我们可以查看当前是否有未完成的IRP。综上所述,排查CloseHandle缓慢的步骤:1.使用!handle00列出所有句柄,观察是否有异常。2.对可疑句柄使用!handle<handle>f获取详细信息,关注引用计数。3.如果是文件句柄,使用!fileobj<对象地址>查看未完成IRP。4.如果是线程或进程句柄,注意线程/进程是否已经终止(未终止的线程/进程不会导致CloseHandle阻塞,除非有未完成的操作,但通常不会)。5.使用WPA进行性能跟踪,捕获CloseHandle调用时的内核堆栈,分析等待事件。引用[1]中提到的WinDbg!handle命令是基础,引用[3]中的xperf命令(即WPA的前端)是更深入分析的工具。最后,根据引用[1]中的最佳实践,在代码中应确保异步I/O操作完成或显式取消后再关闭句柄,避免阻塞。</think>### 在 WinDbg 中使用 `!handle` 命令排查 CloseHandle 调用缓慢问题 #### 排查步骤及命令详解 1. **获取目标进程句柄列表** ```bash !handle 0 0 # 列出所有句柄的摘要信息 ``` **输出解析**: ``` Handle 0000000000000004 Type File GrantedAccess 0x120089 HandleCount 2 PointerCount 3 Name \Device\HarddiskVolume2\test.txt ``` - **关键字段**: - `HandleCount`:用户模式引用计数(>1 表示存在未释放引用) - `PointerCount`:内核模式总引用计数 - `Name`:对象关联资源路径(用于识别阻塞源) 2. **查看特定句柄的详细信息** ```bash !handle <HandleValue> f # 示例:!handle 0000000000000004 f ``` **关键诊断点**: - **引用计数异常**: ``` Object Specific Information File Object 0xffffe001a1b2b080 CurrentByteOffset 0 ``` `PointerCount` 值高表示存在未释放引用[^1] - **未完成 I/O 操作**: ``` Flags 0x40000 Asynchronous I/O ``` 出现 `Asynchronous I/O` 标志需检查挂起操作 3. **检查内核对象引用** ```bash !object <ObjectAddress> # 从!handle输出获取对象地址 ``` **输出分析**: ``` Object: ffffe001a1b2b080 Type: (ffff9480f1d0b0c0) File HandleCount: 1 PointerCount: 3 ``` `PointerCount > HandleCount` 表明存在内核驱动未释放引用 4. **定位 I/O 阻塞源** ```bash !irpfind <ObjectAddress> # 查找关联的IRP包 !irp <IrpAddress> # 分析I/O状态 ``` **阻塞场景判断**: - `Irp->CurrentLocation != 0`:I/O 未完成 - `Irp->Cancel = true`:取消操作被挂起 #### 典型问题诊断案例 1. **异步 I/O 未完成** ```bash !handle 0 0 # 发现文件句柄Flags含"Asynchronous I/O" !thread # 查看线程状态 !irpfind # 查找挂起IRP ``` **解决方案**: ```c CancelIoEx(hFile, NULL); // 显式取消I/O CloseHandle(hFile); ``` 2. **对象引用泄漏** ```bash !handle 000000000000000c f # 输出:PointerCount=5, HandleCount=1 !object ffffe001a1b2b080 ``` **解决方法**: - 检查跨进程 `DuplicateHandle()` 调用 - 使用 Process Explorer 定位持有者进程 3. **驱动资源阻塞** ```bash !handle <DeviceHandle> f # 输出含"\Driver\AVDriver"等第三方驱动名 !locks # 检查内核锁争用 ``` **处理建议**: - 更新或禁用问题驱动 - 检查驱动过滤栈 `!filtarget` #### 诊断流程图 ```mermaid graph TD A[CloseHandle卡顿] --> B[!handle 0 0] B --> C{存在高引用计数?} C -->|是| D[!object 分析内核引用] C -->|否| E{存在异步I/O标志?} E -->|是| F[!irpfind 查挂起操作] E -->|否| G[检查系统资源瓶颈] D --> H[定位未释放的引用源] F --> I[取消或等待I/O完成] G --> J[检查内存/锁争用] ``` #### 补充工具建议 1. **实时监控**: ```bash .logopen c:\handle_log.txt # 开启日志记录 !htrace -enable # 启用句柄跟踪 # 重现问题后 !htrace -snapshot # 分析句柄变化 ``` 2. **性能分析**: ```bash xperf -on PROC_THREAD+LOADER -stackwalk CloseHandle ``` 捕获内核调用栈(需 WPA 工具分析)[^3] 通过上述方法,可精确识别 CloseHandle 阻塞的根本原因,针对性解决句柄泄露、异步 I/O 未完成或驱动兼容性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值