C++ COM 服务器内存使用量随着时间的推移而增加 - 使用 WinDBG 的分析
C++ COM server memory usage increases over time - analisys with WinDBG
我在使用 ATL COM 服务器时遇到问题,该服务器随着时间的推移会占用大量内存。我怀疑内存泄漏,但我无法确定原因。该服务在 48 小时压力测试过程中缓慢添加内存。
这是我在 WinDBG 中通过分析 1 小时后的过程收集的内容。我在这里放置了一些占据大部分内存的对象。
size #blocks total ( %) (percent of total busy bytes)
190 6c3 - a90b0 (32.86)
30 1507 - 3f150 (12.26)
!heap -flt s 190
!heap -p -a 0000000002ae0ee0
address 0000000002ae0ee0 found in
_HEAP @ 1a40000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0000000002ae0eb0 001c 0000 [00] 0000000002ae0ee0 00190 - (busy)
combase!CStdIdentity::`vftable'
7ffd1aa71be7 ntdll!RtlAllocateHeap+0x000000000006fb17
7ffd18676158 combase!CIDObject::GetOrCreateStdID+0x0000000000000128
7ffd1867a788 combase!CDestObjectWrapper::MarshalInterface+0x00000000000006ca
7ffd186795c2 combase!CoMarshalInterface+0x00000000000001a2
7ffd1868145f combase!MarshalHelperMulti+0x000000000000006f
7ffd1868139f combase!GetInstanceHelperMulti+0x0000000000000083
7ffd18681129 combase!CObjServer::CreateInstance+0x0000000000000467
7ffd18b02385 RPCRT4!Invoke+0x0000000000000065
7ffd18b0ae16 RPCRT4!NdrStubCall2+0x000000000000038b
7ffd18b170eb RPCRT4!NdrStubCall3+0x000000000000014a
7ffd187a05ff combase!CStdStubBuffer_Invoke+0x0000000000000067
7ffd187a04d9 combase!SyncStubInvoke+0x0000000000000306
7ffd18633fc9 combase!CCtxComChnl::ContextInvoke+0x0000000000000279
7ffd187a13ff combase!AppInvoke+0x000000000000018f
7ffd187a0e9b combase!ComInvokeWithLockAndIPID+0x0000000000000661
7ffd187a184e combase!ThreadInvoke+0x0000000000000481
7ffd18b02614 RPCRT4!DispatchToStubInCNoAvrf+0x0000000000000014
7ffd18b02517 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x0000000000000177
7ffd18b16ebf RPCRT4!LRPC_SCALL::DispatchRequest+0x0000000000000531
7ffd18b02cc1 RPCRT4!LRPC_SCALL::HandleRequest+0x0000000000000201
7ffd18b02a97 RPCRT4!LRPC_SASSOCIATION::HandleRequest+0x0000000000000237
7ffd18b01d04 RPCRT4!LRPC_ADDRESS::ProcessIO+0x000000000000036d
7ffd18b01afe RPCRT4!LrpcIoComplete+0x00000000000000ae
7ffd1a9fd394 ntdll!TppAlpcpExecuteCallback+0x0000000000000204
7ffd1a9fb96d ntdll!TppWorkerThread+0x00000000000003ad
7ffd184f15bd KERNEL32!BaseThreadInitThunk+0x000000000000000d
7ffd1aa343d1 ntdll!RtlUserThreadStart+0x000000000000001d
!heap -flt s 30
!heap -p -a 0000000002af5960
address 0000000002af5960 found in
_HEAP @ 1a40000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0000000002af5930 0006 0000 [00] 0000000002af5960 00030 - (busy)
7ffd1aa71be7 ntdll!RtlAllocateHeap+0x000000000006fb17
7ffd1a9e0056 ntdll!RtlpAddDebugInfoToCriticalSection+0x0000000000000012
7ffd1aa79db4 ntdll!RtlInitializeCriticalSectionAndSpinCount+0x0000000000055dd4
7ffd18674b24 combase!CStdIdentity::CStdIdentity+0x00000000000002d4
7ffd1867618d combase!CIDObject::GetOrCreateStdID+0x000000000000015d
7ffd1867a788 combase!CDestObjectWrapper::MarshalInterface+0x00000000000006ca
7ffd186795c2 combase!CoMarshalInterface+0x00000000000001a2
7ffd1868145f combase!MarshalHelperMulti+0x000000000000006f
7ffd1868139f combase!GetInstanceHelperMulti+0x0000000000000083
7ffd18681129 combase!CObjServer::CreateInstance+0x0000000000000467
7ffd18b02385 RPCRT4!Invoke+0x0000000000000065
7ffd18b0ae16 RPCRT4!NdrStubCall2+0x000000000000038b
7ffd18b170eb RPCRT4!NdrStubCall3+0x000000000000014a
7ffd187a05ff combase!CStdStubBuffer_Invoke+0x0000000000000067
7ffd187a04d9 combase!SyncStubInvoke+0x0000000000000306
7ffd18633fc9 combase!CCtxComChnl::ContextInvoke+0x0000000000000279
7ffd187a13ff combase!AppInvoke+0x000000000000018f
7ffd187a0e9b combase!ComInvokeWithLockAndIPID+0x0000000000000661
7ffd187a184e combase!ThreadInvoke+0x0000000000000481
7ffd18b02614 RPCRT4!DispatchToStubInCNoAvrf+0x0000000000000014
7ffd18b02517 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x0000000000000177
7ffd18b16ebf RPCRT4!LRPC_SCALL::DispatchRequest+0x0000000000000531
7ffd18b02cc1 RPCRT4!LRPC_SCALL::HandleRequest+0x0000000000000201
7ffd18b02a97 RPCRT4!LRPC_SASSOCIATION::HandleRequest+0x0000000000000237
7ffd18b01d04 RPCRT4!LRPC_ADDRESS::ProcessIO+0x000000000000036d
7ffd18b01afe RPCRT4!LrpcIoComplete+0x00000000000000ae
7ffd1a9fd394 ntdll!TppAlpcpExecuteCallback+0x0000000000000204
7ffd1a9fb96d ntdll!TppWorkerThread+0x00000000000003ad
7ffd184f15bd KERNEL32!BaseThreadInitThunk+0x000000000000000d
7ffd1aa343d1 ntdll!RtlUserThreadStart+0x000000000000001d
其他对象:
size #blocks total ( %) (percent of total busy bytes)
48 6c2 - 1e690 (91.91)
1000 1 - 1000 (3.02)
!heap -flt s 48
!heap -p -a 0000000002ab8000
address 0000000002ab8000 found in
_HEAP @ 1a40000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0000000002ab7fd0 0007 0000 [00] 0000000002ab8000 00048 - (busy)
combase!g_ForwardingVtbl
7ffd1aa71be7 ntdll!RtlAllocateHeap+0x000000000006fb17
7ffd18674115 combase!CreateStubFromTypeInfo+0x0000000000000061
7ffd18b58f63 RPCRT4!CreateStubFromTypeInfo+0x0000000000000043
7ffd1908dcf8 OLEAUT32!CUnivStubWrapper::Invoke+0x0000000000000098
7ffd187a04d9 combase!SyncStubInvoke+0x0000000000000306
7ffd18633fc9 combase!CCtxComChnl::ContextInvoke+0x0000000000000279
7ffd187a13ff combase!AppInvoke+0x000000000000018f
7ffd187a0e9b combase!ComInvokeWithLockAndIPID+0x0000000000000661
7ffd187a184e combase!ThreadInvoke+0x0000000000000481
7ffd18b02614 RPCRT4!DispatchToStubInCNoAvrf+0x0000000000000014
7ffd18b02517 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x0000000000000177
7ffd18b16ebf RPCRT4!LRPC_SCALL::DispatchRequest+0x0000000000000531
7ffd18b02cc1 RPCRT4!LRPC_SCALL::HandleRequest+0x0000000000000201
7ffd18b02a97 RPCRT4!LRPC_SASSOCIATION::HandleRequest+0x0000000000000237
7ffd18b01d04 RPCRT4!LRPC_ADDRESS::ProcessIO+0x000000000000036d
7ffd18b01afe RPCRT4!LrpcIoComplete+0x00000000000000ae
7ffd1a9fd394 ntdll!TppAlpcpExecuteCallback+0x0000000000000204
7ffd1a9fb96d ntdll!TppWorkerThread+0x00000000000003ad
7ffd184f15bd KERNEL32!BaseThreadInitThunk+0x000000000000000d
7ffd1aa343d1 ntdll!RtlUserThreadStart+0x000000000000001d
!heap -p -a 000000000282f280
address 000000000282f280 found in
_HEAP @ 20a0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
000000000282f250 0007 0000 [00] 000000000282f280 00048 - (busy)
ccprovsp!ATL::CComObject<MyCOM>::`vftable'
7ffd1aa71be7 ntdll!RtlAllocateHeap+0x000000000006fb17
140028c87 ccprovsp!malloc+0x0000000000000067
14002815e ccprovsp!operator new+0x000000000000000e
14000280b ccprovsp!ATL::CComCreator<ATL::CComObject<MyCOM> >::CreateInstance+0x000000000000005b
14000239c ccprovsp!ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<MyCOM> >,ATL::CComFailCreator<-2147221232> >::CreateInstance+0x000000000000002c
1400085a7 ccprovsp!ATL::CComClassFactory::CreateInstance+0x0000000000000077
7ffd1868134c combase!GetInstanceHelperMulti+0x0000000000000034
7ffd18681129 combase!CObjServer::CreateInstance+0x0000000000000467
7ffd18b02385 RPCRT4!Invoke+0x0000000000000065
7ffd18b0ae16 RPCRT4!NdrStubCall2+0x000000000000038b
7ffd18b170eb RPCRT4!NdrStubCall3+0x000000000000014a
7ffd187a05ff combase!CStdStubBuffer_Invoke+0x0000000000000067
7ffd187a04d9 combase!SyncStubInvoke+0x0000000000000306
7ffd18633fc9 combase!CCtxComChnl::ContextInvoke+0x0000000000000279
7ffd187a13ff combase!AppInvoke+0x000000000000018f
7ffd187a0e9b combase!ComInvokeWithLockAndIPID+0x0000000000000661
7ffd187a184e combase!ThreadInvoke+0x0000000000000481
7ffd18b02614 RPCRT4!DispatchToStubInCNoAvrf+0x0000000000000014
7ffd18b02517 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x0000000000000177
7ffd18b16ebf RPCRT4!LRPC_SCALL::DispatchRequest+0x0000000000000531
7ffd18b02cc1 RPCRT4!LRPC_SCALL::HandleRequest+0x0000000000000201
7ffd18b02a97 RPCRT4!LRPC_SASSOCIATION::HandleRequest+0x0000000000000237
7ffd18b01d04 RPCRT4!LRPC_ADDRESS::ProcessIO+0x000000000000036d
7ffd18b01afe RPCRT4!LrpcIoComplete+0x00000000000000ae
7ffd1a9fd394 ntdll!TppAlpcpExecuteCallback+0x0000000000000204
7ffd1a9fb96d ntdll!TppWorkerThread+0x00000000000003ad
7ffd184f15bd KERNEL32!BaseThreadInitThunk+0x000000000000000d
7ffd1aa343d1 ntdll!RtlUserThreadStart+0x000000000000001d
关于我下一步应该做什么的任何提示?
首先,您似乎已经正确设置了 GFlags 来跟踪内存分配。这是一件好事,肯定会有助于解决问题。但是,您发布的对象毫无意义,因为我们无法判断它们当前是否应该使用。
在 WinDbg 中进行分析非常困难,需要大量的手动工作。幸运的是,有UMDH(MSDN(在这种情况下会有所帮助。
如何进行
由于您可以在相对较短的时间内重现问题(1 小时内 600 kB 是可以的(,因此请执行此操作。创建一个方案,在该方案中,您在应用程序中反复达到相同的状态,并且(在您看来(应该再次释放所有内存。超过一小时,始终在达到该状态时创建 UMDH 快照。稍后,分析日志文件(此方法称为"模式 2"(。
UMDH 将按调用堆栈对所有内存分配进行排序。如果您设法绘制一段时间内分配的图表,例如在Excel中,您可能会看到一条正在上升的线。这可能是罪魁祸首。您可以尝试 HeapProfiler 来生成这样的图形(我以前从未使用过它,因为我有自己的工具来创建图形,不幸的是目前还没有准备好发布(。
当您知道丢失的对象类型时,您就知道它被分配到的位置(从调用堆栈(。然后执行代码审查并找到应该发布它的位置。试着弄清楚为什么它没有发布(这是真正困难的部分(。
延伸阅读
Tarik Soulami的《Inside Windows Debugging (Amazaon(》一书在第8章中介绍了UMDH。
您可能还想阅读或收听一些在线教程,例如使用 UMDH 查找用户模式内存泄漏或使用 UMDH 查找内存泄漏。
- 有效地使用std::unordered_map来插入或增加键的值
- C++:功能在输出前自动使用50减/增加输入数
- 如何增加使用 CUDA 实现的 FLOPS
- 使用某些用户输入向量[x]++增加向量的索引
- 避免使用Dynamic_cast而不增加耦合
- UNIX API 调用:使用 read() 函数打开文件并将其打印到屏幕上会增加额外的随机字符
- 在不使用容器或字符串库的情况下,在运行时增加动态数组大小
- 使用碰撞检测来增加SFML 2.4中的游戏分数的问题
- 如何使用difference_type按任何值增加/减少reverse_iterator
- 使用MKL并行SPMV随着螺纹编号的增加而减慢
- 使用迭代器增加
- 使用新线程池而无需重新启动的新线程池后,Jemalloc的内存大大增加
- 使用OpenMP库,执行时间如何取决于线程数量的增加
- 如何使用 c++ 实时数据增加 gnuplot 的绘图频率
- 使用数组增加文件
- 使用“变换”创建增加的向量
- 如何使用pthreads在Solaris上增加C 线程堆栈的大小
- 使用"%"与"&"时差/增加不同
- Arduino:使用按钮增加和减少变量
- C++ COM 服务器内存使用量随着时间的推移而增加 - 使用 WinDBG 的分析