激活上下文导致动态加载的 DLL 上的文件句柄泄漏
我有一个动态加载的&卸载的 DLL 需要 COMCTL32.dll >= v6.0 和 MSVCR >= v9.0。为了确保加载正确的版本,我在 Visual Studio 项目设置中启用清单文件生成,并将此条目添加到另一个清单文件中:
<依赖程序集>
<程序集身份
类型=“win32”
名称=“Microsoft.Windows.Common-Controls”
版本=“6.0.0.0”
处理器架构=“*”
publicKeyToken =“6595b64144ccf1df”
语言=“*”
//>
在测试程序中,我调用该 DLL 的 LoadLibrary()
,然后调用 FreeLibrary()
,ProcessExplorer 指示以下文件句柄是泄露:
- C:\WINDOWS\WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_6f74963e
- C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.55 12_x-ww_35d4ce83
从反汇编调用堆栈跟踪中我了解到 < code>LoadLibrary(),会自动创建一个激活上下文,并打开每个文件夹的句柄。但似乎 FreeLibrary()
上的激活上下文并未被删除。
如果我删除清单文件并将项目设置设置为禁用清单生成,这些泄漏就会消失。但是,这样我将无法确保使用正确的 MSVCR 和 COMCTL,因为该 DLL 是由我无法控制的进程加载的。
有没有办法在不删除清单文件的情况下消除此泄漏?
谢谢!
I have a dynamically loaded & unloaded DLL which requires COMCTL32.dll >= v6.0 and MSVCR >= v9.0. To ensure that the correct versions are loaded, I enable manifest file generation in Visual Studio project setting, and add this entry to another manifest file:
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
In a test program I call LoadLibrary()
followed by FreeLibrary()
of that DLL, and ProcessExplorer indicates that the following File handles were leaked:
- C:\WINDOWS\WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_6f74963e
- C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83
From disassembly call stack trace I learnt that on LoadLibrary()
, an activation context was automatically created and it opens handles to each of these folders. But it appears that the activation context is not deleted on FreeLibrary()
.
If I remove the manifest files and set project settings to disable manifest generation, these leaks are gone. However, that way I will be unable to ensure that the correct MSVCR and COMCTL are used, since this DLL is loaded by processes I have no control over.
Is there a way to remove this leak without removing the manifest files?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
ProcessExplorer HANDLE 泄漏报告是激活上下文泄漏的症状。此泄漏很可能间接发生在您的代码中,因为您没有正确调用 MFC。
为了帮助您自己验证这是您的错误而不是 MFC 的错误,您可以从 AppWizard 创建一个简单的 MFC DLL,而无需任何代码,并确认在多次 LoadLibrary/FreeLibrary 时,没有累积泄漏。
缺少的操作系统调用要么是 ReleaseActCtx,要么是缺少导致发布失败的 DeactivateActCtx。实际上,MFC 会为您调用这些函数,因此您将寻找某种缺失的 MFC 调用。
最好的调试技术可能是跟踪或断点核心激活上下文创建/激活/停用/释放功能(http://msdn.microsoft.com/en-us/library/aa374166(VS.85).aspx)和看看会发生什么。您可能会看到一堆调用,因此可能需要进行某种跟踪。理想情况下,您可以在每次调用时捕获调用堆栈并查看它们。您的调试器也许能够帮助您做到这一点。 VS 的最新版本可以在遇到断点时运行宏。
顺便说一句,您需要清单文件是正确的,并且不应删除它们。
马丁
The ProcessExplorer HANDLE leak reports are a symptom of an activation context leak. Most likely this leak is in your code indirectly in that you've not correctly called MFC.
To help yourself validate that this is your bug and not MFC's, you can create a simple MFC DLL from the AppWizard without any of your code and confirm that when it is LoadLibrary/FreeLibrary several times, there is no accumulative leak.
The missing OS call is either a ReleaseActCtx, or a missing DeactivateActCtx that caused the release to fail. In practice, MFC is calling these functions for you so you'll be looking for a missing MFC call of some kind.
The best debugging technique would probably be to trace or breakpoint the core activation context create/activate/deactivate/release functions (http://msdn.microsoft.com/en-us/library/aa374166(VS.85).aspx) and see what happens. You may see a bunch of calls so some kind of tracing may be necessary. Ideally you might capture the callstack at each call and review them. Your debugger may be able to help you do this. Recent versions of VS can run macros when they hit breakpoints.
As an aside, you are correct that you need the manifest files and should not remove them.
Martyn
ProcessExplorer HANDLE 泄漏报告是激活上下文泄漏的症状。此泄漏很可能间接发生在您的代码中,因为您没有正确调用 MFC。
它与特定代码使用情况无关。 Microsoft 已确认此问题:http://support.microsoft.com/kb/2624911
调用 UnregisterClass 时,SHELL32.DLL 中确实存在上下文激活泄漏,影响了 Windows Vista 及更高版本。该问题的唯一解决方法是不要重复加载和卸载 SHELL32.DLL。 Microsoft 正在寻求在较新版本的 Windows 中解决此问题的方法。
The ProcessExplorer HANDLE leak reports are a symptom of an activation context leak. Most likely this leak is in your code indirectly in that you've not correctly called MFC.
It is not related to specific code usage. The issue has been confirmed by Microsoft: http://support.microsoft.com/kb/2624911
There is indeed a context activation leak in the SHELL32.DLL when calling UnregisterClass, affecting Windows Vista and up. The only work-around to the issue is to not repeatedly load and unload SHELL32.DLL. Microsoft is looking at a fix for this issue in newer versions of Windows.
这些句柄可能不会泄露——只是被缓存了。如果您更改测试程序以多次重复加载和卸载 DLL,您是否会在每次 DLL 卸载时看到一对新的句柄泄漏?如果没有,这不是问题。
These handles may be not leaked -- just cached. If you change your test program to load and unload your DLL repeatedly several times, do you see a new pair of handles leaked every time DLL unloads? If not, it's not an issue.
您的 DLL 有可能使用 MFC 吗?
我遇到了一个使用 MFC 并调用可能相关的
AfxWinInit()
的 DLL 的问题。该 DLL(错误地)重复调用AfxWinInit()
,结果发现它泄漏了每个调用的激活上下文。令人惊讶的是,只有当调用应用程序使用清单时才会发生这种情况。Does your DLL use MFC by any chance?
I had an issue with an DLL which uses MFC and calls
AfxWinInit()
which might be related. This DLL (erroneously) calledAfxWinInit()
repeatedly and it turned out it leaked an activation context for each of these calls. Surprisingly this only happened when the calling application used a manifest.