句柄泄露

 

在linux中一个文件、一个串口、一个socket、一个线程都可以是一个文件,而一个文件会占用一个句柄,linux中一个进程默认的句柄最大数值是1024,当超过这个数值,linux就会对当前的进程进行kill,而kill的对象可以是任意对象,所以会造成各种异常原因的崩溃.

使用linux下的 lsof命令,列出所有占用的句柄,

使用方式如下

1

2

3

4

5

adb shell

 

su

 

lsof

android下的lsof命令就是残废的

handlerThread虽然继承自Thread,但是它里面有looper,所以interrupt是不行的,这里需要调用quit()

通信的心跳service,如果连不上会每隔30s重新创建Connectmanager,并且旧的不销毁!

在重新连接前把旧的销毁掉。

遇到这种问题还是我们写代码不够规范造成的,输入输出流打开了一定要记得关闭,线程开启了如果不用了也要记得回收,还有一些对象如果需要重新初始化,那么旧的不用的对象也要回收,这样才能保证程序能够长久稳定的运行。我想:还好这个项目没有用到数据库,要不然可能还会遇到cursor的泄露

 

asset bundle分组策略/依赖打包/资源重复问题解决方案

  • iOS File Handle Overuse

下一节中描述的问题是在Unity 5.3.2.p2中确定的。当前的统一版本不受这个问题的影响。
在Unity 5.3.2.p2之前的版本中,Unity会在加载AssetBundle的整个时间内,将一个打开的文件句柄保存到一个AssetBundle中。这在大多数平台上都不是问题。然而,iOS限制了一个进程可能同时打开到255的文件句柄的数量。如果加载一个AssetBundle导致这个限制被超过,那么加载调用将会因为“太多的打开文件句柄”错误而失败。
对于试图将其内容划分为数百或数千个assetbundle的项目来说,这是一个常见的问题。
对于无法升级到修补过的统一版本的项目,临时解决方案是:
通过合并相关的assetbundle来减少使用的assetbundle的数量
使用assetbundle.卸载(false)关闭AssetBundle的文件句柄,并手动管理加载的对象的生命周期

 

 

 

<think>我们正在处理一个关于使用WinDbg分析Windows窗体应用程序中的句柄泄漏问题。根据用户的问题,我们需要提供使用WinDbg分析窗体句柄泄漏的方法和步骤。同时,我们需要参考提供的引用内容,特别是引用[1]中提到了使用WinDbg的!handle命令,引用[3]提到了句柄泄漏的影响和检测方法,引用[4]则展示了一个简单的句柄泄漏示例代码。 步骤概述: 1. 准备工作:安装WinDbg,配置符号路径。 2. 启动WinDbg并附加到目标进程。 3. 使用WinDbg命令检测句柄泄漏,特别是窗口句柄(类型为Window)。 4. 分析句柄使用情况,找出未关闭的句柄。 5. 定位代码中创建窗口句柄的位置,以便修复。 详细步骤: 步骤1:准备工作 - 安装WinDbg(建议最新版本,可从Microsoft Store或Windows SDK中获取)。 - 设置符号路径:在WinDbg中,通过菜单或命令设置符号路径,确保可以下载Microsoft的公共符号。可以使用命令: .sympath srv*https://msdl.microsoft.com/download/symbols 然后执行: .reload 步骤2:附加到目标进程 - 启动目标应用程序(有窗体句柄泄漏的应用程序)。 - 打开WinDbg,选择“文件”->“附加到进程”,选择目标进程。 - 或者使用命令行启动:windbg -p <PID> 步骤3:使用!handle命令获取句柄信息 - 在WinDbg中,我们可以使用`!handle`命令来查看进程的句柄信息。为了专门查看窗口句柄,我们可以指定句柄类型。窗口句柄的类型在Windows中通常为`Window`(注意:在Windows中,窗口句柄的类型名称是“Window”,但实际在句柄表中,窗口句柄的类型是`WindowStation`、`Desktop`和`Window`等,但通常我们关心的窗体句柄类型是`Window`)。 - 然而,在句柄表中,窗口句柄的类型实际上是`Window`对象。我们可以使用以下命令: !handle 0 0 Window 这个命令会列出所有类型为Window的句柄。 - 但是,由于句柄类型很多,我们也可以先查看所有句柄的统计信息,以确定窗口句柄的数量和类型: !handle 0 0 步骤4:跟踪句柄的创建和关闭 - 为了检测泄漏,我们需要在程序运行过程中多次捕获句柄快照,并比较窗口句柄数量的变化。如果窗口句柄数量持续增加,则存在泄漏。 - 方法: a. 在程序启动后不久,捕获一次句柄快照(使用`!handle 0 0 Window`记录句柄数量)。 b. 执行一些操作(比如打开和关闭窗口)后,再次捕获快照。 c. 重复几次,观察窗口句柄数量是否持续增加。 - 另外,我们可以使用`!htrace`命令(句柄跟踪)来跟踪句柄的创建和关闭。这个命令需要启用跟踪,然后可以查看未关闭的句柄的创建堆栈。 - 启用句柄跟踪:`!htrace -enable` - 然后让程序运行一段时间(执行一些操作)。 - 然后再次执行`!htrace -snapshot`来拍摄当前句柄的快照。 - 再运行一段时间后,执行`!htrace -diff`来比较快照之间的差异,找出在此期间新创建但未关闭的句柄。 - 对于每个泄漏的句柄,我们可以使用`!htrace <handle_value>`来查看创建该句柄时的堆栈。 步骤5:分析堆栈,定位代码 - 通过`!htrace`命令得到的堆栈信息,我们可以找到创建窗口句柄的代码位置。堆栈会显示调用序列,包括函数名和偏移量。 - 注意:需要加载正确的符号(包括应用程序的符号和系统符号)才能看到有意义的函数名。 步骤6:修复问题 - 根据堆栈信息,找到代码中创建窗口句柄的地方(例如,调用`CreateWindowEx`),并确保在窗口销毁时正确关闭句柄(通常通过`DestroyWindow`函数,但注意,窗口句柄的关闭通常由系统管理,然而如果我们在创建窗口后没有正确销毁窗口,就会导致句柄泄漏。另外,注意窗口类、窗口过程等是否正确处理了销毁消息)。 注意事项: - 窗体句柄泄漏通常是因为窗口没有被正确销毁。在Windows中,每个窗口都有一个句柄,当窗口被销毁时,句柄会被系统回收。因此,确保在不需要窗口时调用`DestroyWindow`。 - 另外,也要注意窗口消息循环的正确处理,确保在窗口关闭消息(如WM_CLOSE)中执行了销毁操作。 示例代码分析(引用[4]): - 在引用[4]中,fun4函数创建了一个事件句柄但没有关闭,这会导致事件句柄泄漏。虽然这个例子不是窗口句柄,但原理类似。窗口句柄的泄漏通常是因为没有调用DestroyWindow,而不是CloseHandle(注意:窗口句柄不能使用CloseHandle关闭,必须使用DestroyWindow)。 因此,对于窗体句柄泄漏,我们应该查找程序中创建窗口的地方,并确保在不需要窗口时调用DestroyWindow。 相关问题: 根据用户的问题,我们生成以下相关问题: 1. 在WinDbg中,如何区分不同类型的句柄(如文件句柄、窗口句柄)? 2. 除了WinDbg,还有哪些工具可以检测Windows窗体句柄泄漏? 3. 如何通过代码避免窗体句柄泄漏? 4. 在C#应用程序中,如何调试窗体句柄泄漏? 现在,我们将按照上述步骤详细说明如何用WinDbg分析窗体句柄泄漏。</think>### WinDbg分析Windows窗体句柄泄漏的方法与步骤 #### 核心原理 窗体句柄泄漏指程序持续创建窗口对象(`HWND`)但未调用`DestroyWindow()`释放资源。每次泄漏会增加系统GDI对象计数,当超过阈值(通常10,000个)时程序崩溃[^3]。WinDbg通过句柄追踪和堆栈分析定位泄漏点。 --- ### 分析步骤 #### 1. **准备环境** - 安装[Windows SDK](https://developer.microsoft.com/zh-cn/windows/downloads/windows-sdk/)(包含WinDbg) - 配置符号路径(管理员权限运行): ```bash .sympath srv*https://msdl.microsoft.com/download/symbols .reload /f ``` #### 2. **附加目标进程** ```bash windbg -pn YourApp.exe # 通过进程名附加 windbg -p <PID> # 通过进程ID附加 ``` #### 3. **启用句柄追踪** ```bash !htrace -enable # 激活句柄跟踪 g # 继续运行程序 ``` #### 4. **捕获句柄快照** ```bash !htrace -snapshot # 创建初始快照 # 执行疑似泄漏的操作(如反复打开/关闭窗口) !htrite -snapshot # 创建第二次快照 !htrace -diff # 对比快照差异 ``` 输出示例: ``` Handles new opened: Handle 0x274, type Window, stack: ntdll!NtUserCreateWindowEx+0x14 win32u!CreateWindowEx+0x1f3 USER32!CreateWindowExW+0x79 YourApp!CreateMainWindow+0x42 [c:\source\window.cpp @ 105] ... ``` #### 5. **分析泄漏点** - **定位代码**:查看堆栈中`YourApp!`开头的函数(如`YourApp!CreateMainWindow+0x42`) - **检查句柄类型**:确认泄漏句柄类型为`Window` - **验证泄漏**: ```bash !handle 0x274 f # 查看具体句柄信息 ``` #### 6. **修复验证** - 在代码中确保每个`CreateWindowEx()`对应`DestroyWindow()` - 使用`!htrace -disable`关闭跟踪后重新测试 --- ### 关键命令详解 | 命令 | 用途 | |------|------| | `!handle 0 0 Window` | 列出所有窗口句柄 | | `!htrace <handle>` | 查看句柄创建堆栈 | | `!gdi` | 检查GDI对象计数 | | `.hh !htrace` | 查看命令帮助文档 | --- ### 常见泄漏场景 1. **模态窗口未销毁** ```c HWND hDlg = CreateDialog(...); ShowWindow(hDlg, SW_SHOW); // 缺少EndDialog销毁 ``` 2. **动态控件未释放** ```c for(int i=0; i<100; i++) { CreateWindow("BUTTON", ...); // 循环中创建按钮 } // 未在父窗口销毁时自动删除 ``` 3. **消息处理缺陷** 未正确处理`WM_DESTROY`消息: ```c case WM_CLOSE: DestroyWindow(hWnd); // 必须调用 break; ``` --- ### 辅助工具推荐 1. **任务管理器**:进程详情页查看"句柄数"趋势 2. **Process Explorer**:实时监控句柄类型统计 3. **GDIView**(NirSoft):专项分析GDI对象泄漏 > 提示:窗体句柄泄漏常伴随USER对象/GDI对象增长,需结合`!gdi`和`!user`命令综合分析[^1][^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值