为什么我的 COM 工厂在程序生命周期内从未被释放?
我有一个本机 C++ ATL 进程内 COM 服务器。一个单独的测试程序
- 调用
CoInitialize()
, - 调用
CoCreateInstance()
,然后 - 对指针调用
Release()
, - 然后调用
CoUnitialize ()
并退出。
如果我在 Visual C++ 调试器下运行测试程序,调试 CRT 会报告单个内存泄漏,并且每次分配编号都是相同的。
我使用分配挂钩并发现没有返回到堆的对象是类工厂对象。
因此,基本上会发生以下情况:
- 程序调用
CoCreateInstance()
- COM 内部调用
DllGetClassObject()
- ATL 实例化工厂并将所有权传递给调用者(COM 内部)
,然后传递给工厂从未发布 - 我没有看到对类工厂的 Release()
的足够调用。
怎么了?这是 COM 运行时的缺陷吗?
I have a native C++ ATL in-proc COM server. A separate test program
- calls
CoInitialize()
, - calls
CoCreateInstance()
, then - calls
Release()
on the pointer, - then calls
CoUnitialize()
and exits.
If I run the test program under Visual C++ debugger the debug CRT reports a single memory leak and each time the allocation number is the same.
I used an allocation hook and found out that the object not being returned to the heap is the class factory object.
So basically the following happens:
- the program calls
CoCreateInstance()
- COM internally calls
DllGetClassObject()
- ATL instantiates the factory and passes ownership to the caller (COM internals)
and then the factory is never released - I don't see enough calls to Release()
of the class factory.
What is happening? Is that a defect in COM runtime?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
原来是ATL实现的问题。
服务器使用全局
CComModule
类实例。当调用CComModule::DllClassObject()
时,它会创建一个类工厂实例并将其缓存在CComModule
对象引用的映射中。所以实际上CComModule
对象拥有类工厂。当 CComModule 析构函数运行时,它不会释放缓存的类工厂。为了释放所有缓存的类工厂,应在卸载服务器之前调用
CComModule::Term()
方法。 IMO 实现此目的的最简洁方法是从CComModule
派生并在派生类析构函数中调用CComModule::Term()
。Turns out it's a problem of ATL implementation.
The server uses a global
CComModule
class instance. WhenCComModule::DllClassObject()
is called it creates a class factory instance and caches it in the map referenced by theCComModule
object. So in factCComModule
object owns the class factory. WhenCComModule
destructor runs it doesn't release cached class factories.In order to release all cached class factories
CComModule::Term()
method should be called before the server is unloaded. IMO the cleanest way to achieve this is to derive fromCComModule
and callCComModule::Term()
in the derived class destructor.