COM Dll 引用是否需要手动处理?如果是这样,怎么办?
我在 VB 中编写了一些代码,用于验证 Windows 防火墙中的特定端口是否打开,否则打开一个端口。该代码使用对三个 COM DLL 的引用。我编写了一个 WindowsFirewall 类,它导入 DLL 定义的主命名空间。在 WindowsFirewall 类的成员中,我构造了一些由引用的 DLL 定义的类型。以下代码不是整个课程,但演示了我正在做的事情。
Imports NetFwTypeLib
Public Class WindowsFirewall
Public Shared Function IsFirewallEnabled as Boolean
Dim icfMgr As INetFwMgr
icfMgr = CType(System.Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwMgr")), INetFwMgr)
Dim profile As INetFwProfile
profile = icfMgr.LocalPolicy.CurrentProfile
Dim fIsFirewallEnabled as Boolean
fIsFirewallEnabled = profile.FirewallEnabled
return fIsFirewallEnabled
End Function
End Class
我不经常引用 COM DLL。我读到非托管代码可能不会被垃圾收集器清理,我想知道如何确保我没有引入任何内存泄漏。请告诉我 (a) 是否引入了内存泄漏,以及 (b) 如何清理它。
(我的理论是 icfMgr 和 profile 对象确实会分配在应用程序关闭之前保持未释放的内存。我希望将它们的引用设置为空会将它们标记为垃圾回收,因为我找不到其他方法来处理它们两者都没有实现 IDisposable,也不包含 Finalize 方法,我怀疑它们甚至可能与这里无关,并且这两种释放内存的方法仅适用于 .Net 类型。)
I have written some code in VB that verifies that a particular port in the Windows Firewall is open, and opens one otherwise. The code uses references to three COM DLLs. I wrote a WindowsFirewall class, which Imports the primary namespace defined by the DLLs. Within members of the WindowsFirewall class I construct some of the types defined by the DLLs referenced. The following code isn't the entire class, but demonstrates what I am doing.
Imports NetFwTypeLib
Public Class WindowsFirewall
Public Shared Function IsFirewallEnabled as Boolean
Dim icfMgr As INetFwMgr
icfMgr = CType(System.Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwMgr")), INetFwMgr)
Dim profile As INetFwProfile
profile = icfMgr.LocalPolicy.CurrentProfile
Dim fIsFirewallEnabled as Boolean
fIsFirewallEnabled = profile.FirewallEnabled
return fIsFirewallEnabled
End Function
End Class
I do not reference COM DLLs very often. I have read that unmanaged code may not be cleaned up by the garbage collector and I would like to know how to make sure that I have not introduced any memory leaks. Please tell me (a) if I have introduced a memory leak, and (b) how I may clean it up.
(My theory is that the icfMgr and profile objects do allocate memory that remains unreleased until after the application closes. I am hopeful that setting their references equal to nothing will mark them for garbage collection, since I can find no other way to dispose of them. Neither one implements IDisposable, and neither contains a Finalize method. I suspect they may not even be relevant here, and that both of those methods of releasing memory only apply to .Net types.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不知道这里该推荐什么。这里绝对没有内存泄漏,垃圾收集器释放 COM 引用计数。 COM 对象不是一次性的,但您可以使用 Marshal.ReleaseComObject() 提前释放它们。显式执行此操作的麻烦在于,通常非常很难跟踪接口引用。
例如,在您的代码片段中,在 icfMgr 上调用 ReleaseComObject 将不会产生任何效果。 LocalPolicy 成员有一个隐藏的引用,可以使接口引用保持活动状态。您还必须对该隐藏引用调用 ReleaseComObject。
我根本不建议将此作为一种做法。出错会导致难以诊断的故障,您实际上又回到了显式内存管理的糟糕旧时代。但在你的具体例子中它是可以管理的。
Not sure what to recommend here. There is most definitely no memory leak here, the garbage collector releases COM reference counts. COM objects are not disposable but you can release them early with Marshal.ReleaseComObject(). The trouble with doing this explicitly is that it is normally very hard to track interface references.
In your code snippet for example, calling ReleaseComObject on the icfMgr won't have any effect. There's a hidden reference through the LocalPolicy member that will keep the interface reference alive. You'd have to call ReleaseComObject on that hidden reference as well.
I would not recommend making this a practice at all. Getting it wrong produces hard to diagnose failure, you're essentially back to the bad old days of explicit memory management. But it is somewhat manageable in your specific example.
你是完全正确的:非托管代码无法被管理,因此需要手动管理:处置。然而,这很大程度上取决于您正在做什么,但在许多情况下,将对象实例化包装在 using 块周围就足够了。仅当您使用实现 IDisposable 的对象时,此方法才有效。
但是,按照当前创建 COM 对象实例的方式,您将无法轻松清理。这取决于对象。当它不需要清理时(检查FwMgr的析构函数),它也不需要处置。然而,大多数 COM 对象确实需要处置。
那么,如何将 IDisposable 接口添加到本身不支持它的 COM 对象中呢?手动执行此操作需要一些工作,但您应该创建一个包装器 .NET 程序集。幸运的是,这项工作已经从我们手中夺走了,微软已经创建了一些工具和指南。
其中一些信息也包含在此处。您可能还想查找 WeakReference 作为替代方案。
请注意,COM 和 .NET 不能很好地协同工作,但它们确实可以相互交流。一个很好的参考资料是 SAMS Publishing 的 Don Box 所著的 .NET 和 COM 完整互操作性指南。
编辑:
回答你的“内存泄漏”问题:无法判断你是否引入了内存泄漏,以及它有多大。这取决于您调用 COM 对象的频率。每个正在运行的进程调用一次?别太担心。在内循环中调用它数百次?要非常小心。想确定吗?查找原始文档或来源:如果它在被破坏时释放句柄、内存或其他资源,那么是的,您引入了泄漏。
You are exactly right: unmanaged code cannot be managed and thus needs to be managed by hand: disposed of. However, this greatly depends on what you are doing, but in many cases, it is sufficient to wrap the object instantiation around a Using-block. This only works if you use an object that implements
IDisposable
.However, the way you currently create an instance of a COM object, you will not have the possibility to clean up easily. It depends on the object. When it doesn't need cleaning up (check the destructor of FwMgr), it doesn't need disposing either. However, most COM objects do need disposal.
So, how to add the
IDisposable
interface to a COM object that doesn't natively support it? It's a bit of work to do so manually, but you should create a wrapper .NET assembly. Luckily, the work has been taken out of our hands and Microsoft has created some tools and guidelines.Some of this information is covered here too. You may want to also look up WeakReference as an alternative.
Note that COM and .NET do not talk well together, but they do talk. An excellent reference is .NET and COM The Complete Interoperability Guide by Don Box, SAMS Publishing.
EDIT:
In answer to your "memory leak" question: it is impossible to tell whether you introduced a memory leak, and how big it is. It depends on how often you call your COM object. Call it once per running process? Don't worry too much. Call it hundredths of times in an inner loop? Be very careful. Want to know for sure? Lookup the original documentation or source: if it releases handles, memory or other resources when it is destructed, then yes, you introduced a leak.