赞
踩
ProcExp是微软提供的一款进程浏览器工具,他是对任务管理器的增强;通过它我们可以查看系统的运行情况,包括但不限于:
最近在使用这个软件的时候发现该软件占用内存非常大,导致本人16GB的菜鸡电脑运行非常卡慢,如下示意图:
这里ProxExp占用了1GB以上的内存,这个绝对是异常的情况;理论来说作为SysinternalsSuite来说应该是不会产生内存泄漏这种通用性的问题,那么是什么导致ProxExp占用这么高的内存呢?本文来分析一下具体原因。
作为开发人员,这里直接使用WinDbg来排查(当然还可以使用一些更加简单的工具)。因为大部分情况下,占用内存太高都是堆内存使用过高导致的,我们直接查看堆内存的占用情况:
0:005> !heap -s ************************************************************************************************************************ NT HEAP STATS BELOW ************************************************************************************************************************ NtGlobalFlag enables following debugging aids for new heaps: stack back traces LFH Key : 0x6f02eff3e12c8d31 Termination on corruption : ENABLED Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast (k) (k) (k) (k) length blocks cont. heap ------------------------------------------------------------------------------------- 000001eaf44f0000 08000002 49132 43604 48740 709 583 7 1 1c LFH 000001eaf2ad0000 08008000 64 4 64 2 1 1 0 0 000001eaf4480000 08001002 3516 1544 3124 1360 25 3 0 0 LFH External fragmentation 88 % (25 free blocks) 000001eaf5fb0000 08001002 1472 100 1080 10 10 2 0 0 LFH 000001eaf64c0000 08001002 452 36 60 6 5 1 0 0 LFH 000001eaf6830000 08001002 452 32 60 7 4 1 0 0 LFH 000001eac26e0000 08001002 452 48 60 7 4 1 0 0 LFH -------------------------------------------------------------------------------------
从上面来看,我们在堆上面分配的内存没有任何问题,虚拟内存只有48MB,这对于一个在Windows11环境下面运行的UI程序来说是不算多的。
但是我们这里可以看到有一个虚拟内存块,那么是否是这个虚拟内存块导致的内存太大了呢?我们看一下000001eaf44f0000
这个堆上面内存的情况,如下:
0:005> !heap -stat -h 000001eaf44f0000 heap @ 000001eaf44f0000 group-by: TOTSIZE max-display: 20 size #blocks total ( %) (percent of total busy bytes) 40000000 1 - 40000000 (96.76) 3c00 223 - 803400 (0.76) 5d0 1202 - 68aba0 (0.62) 1e00 118 - 20d000 (0.19) d8080 1 - d8080 (0.08) d65a0 1 - d65a0 (0.08) d3df8 1 - d3df8 (0.08) 360 360 - b6400 (0.07) b6374 1 - b6374 (0.07) 6c8 19b - ae318 (0.06) 8d80 10 - 8d800 (0.05) 28 301c - 78460 (0.04) 1436 2b - 36512 (0.02) 48 ab5 - 302e8 (0.02) 800 58 - 2c000 (0.02) 2bca3 1 - 2bca3 (0.02) 30 e98 - 2bc80 (0.02) 143a 22 - 2afb4 (0.02) 2ad08 1 - 2ad08 (0.02) 29180 1 - 29180 (0.02)
果然是的,这里分配了一块很大的内存40000000
,这个内存大小如下:
0:005> ? 40000000
Evaluate expression: 1073741824 = 00000000`40000000
这一块内存就有1GB往上,那么整个ProcExp工具占用内存过高就是这块内存太大导致的。
从上面内存分析,我们似乎可以得出ProxExp这个工具真的有BUG,导致内存占用够大,下面我们查一下具体原因。
首先,我们对内存分配的函数下断点,查找到分配这块内存的地方:
bp ntdll!NtAllocateVirtualMemory ".if (qwo(@r9) >= 0x40000000){} .else{gc;}"
运行程序,顺利在断点处中断了程序的运行,此时堆栈信息如下:
0:000> kb
# RetAddr : Args to Child : Call Site
00 00007ffa`6d2662fe : 00000000`00000000 00007ffa`6d2ee4f8 000004f0`fffffb30 000004d0`fffffb30 : ntdll!NtAllocateVirtualMemory
01 00007ffa`6d20c0ff : 00000199`0aa90000 00000000`00000000 00000000`0000a000 00000023`14efea38 : ntdll!RtlpHpAllocVirtBlockCommitFirst+0x56
02 00007ffa`6d20929c : 00000199`0aa90000 00000199`00000002 00000000`40000020 00000000`40000068 : ntdll!RtlpAllocateHeap+0xf9f
03 00007ff7`46183fe8 : 00000000`00000001 00000000`40000000 00000000`00009720 00000000`00000000 : ntdll!RtlpAllocateHeapInternal+0x6ac
04 00007ff7`46144333 : 00000000`00000001 00000000`00000000 00000000`00000001 00000000`00000000 : procexp64+0x103fe8
05 00007ff7`46144a89 : 00000023`28618060 00000199`0c660000 00000000`0000043c 00000000`00009720 : procexp64+0xc4333
06 00007ff7`460f3ccd : 00007ff7`46080000 00007ff7`46229580 00000000`00009720 00000000`0000000a : procexp64+0xc4a89
07 00007ff7`4615dab3 : 00007ff7`461f9580 00007ff7`46229580 00000000`00009720 00007ff7`46229580 : procexp64+0x73ccd
08 00007ff7`46161d0a : 00000000`00000000 00000000`0000000a 00000000`00000000 00000000`00000000 : procexp64+0xddab3
09 00007ffa`6b0653e0 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : procexp64+0xe1d0a
0a 00007ffa`6d1e485b : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x10
0b 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x2b
通过NtAllocateVirtualMemory
参数查看分配内存的请求大小,如下:
0:000> dq @r9 L1
00000023`14efea10 00000000`4000b068
这正是我们上面分析的大内存,因此证明这个堆栈是正确的。我们查看ProcExp的反汇编代码,发现分配内存的代码如下:
通过MessageBox
处的日志"Insufficient system resources to get handle information"我们可以猜测出,这里是ProxExp在获取句柄信息的时候分配了太多的内存导致的。产生这个问题有两个原因:
下面我们分析一下具体是那个原因导致的。
通过上述的反汇编代码我们可以得知并猜测两个原因:
那么我们直接来排查系统应该有那么多句柄信息需要获取,我们使用ProxExp查看一下系统中进程的句柄信息,使用如下选项:
根据Handles列排序之后,我们可以发现一个进程使用句柄非常多,如下:
这个进程完整路径为"C:\Program Files\ASUS\AacMB\Aac3572MbHal_x86.exe",这个是华硕的一个进程,我用的华硕的主板,可能是默认安装的程序,如下:
我们把这个进程结束掉,然后重启ProcExp,进程内存正常,如下:
至此,我们分析了该问题产生的原因,是因为Aac3572MbHal_x86.exe分配句柄太多导致的;至于Aac3572MbHal_x86.exe分配句柄太多的BUG,不再此深入分析,卸载该软件即可。
ProcExp软件运行内存过高这个问题分析起来虽然不困难,但是这个是作为一个软件问题分析的典型,在这里文章记录一下相关过程,如果有更好的排查思路,希望大家能够指正和交流。
当然这也是软件开发中一个典型的城门失火,殃及鱼池的案例。Aac3572MbHal_x86.exe泄漏了太多的句柄,没有被使用者发现,但是殃及了ProcExp使用了太多的内存,从而引发的一系列问题。
那么是否真的就是Aac3572MbHal_x86.exe这款软件自己的BUG导致句柄的泄漏,还是另外其他的模块导致的呢?这里并不做详细分析,也许Aac3572MbHal_x86.exe并不是真正的源头呢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。