我在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类型。)
答案 0 :(得分:2)
不确定这里推荐什么。这里肯定没有内存泄漏,垃圾收集器释放COM引用计数。 COM对象不是一次性的,但您可以使用Marshal.ReleaseComObject()尽早释放它们。明确地这样做的麻烦在于,通常非常难以跟踪接口引用。
例如,在代码片段中,在icfMgr上调用ReleaseComObject将不会产生任何影响。通过LocalPolicy成员有一个隐藏的引用,它将使接口引用保持活动状态。您还必须在该隐藏引用上调用ReleaseComObject。
我不建议将其作为一种练习。错误导致难以诊断失败,您基本上回到了显式内存管理的旧时代。但是在你的具体例子中它有些可管理。
答案 1 :(得分:0)
你是完全正确的:无法管理非托管代码,因此需要手工管理:处理掉。但是,这在很大程度上取决于您正在做什么,但在许多情况下,将对象实例化包装在Using-block周围就足够了。这仅适用于使用实现IDisposable
的对象。
但是,当前创建COM对象实例的方式,您将无法轻松清理。这取决于对象。当它不需要清理时(检查FwMgr的析构函数),它也不需要处理。但是,大多数COM对象都需要处理。
那么,如何将IDisposable
接口添加到本身不支持它的COM对象?手动执行此操作需要做一些工作,但是您应该创建一个包装器.NET程序集。幸运的是,这项工作已经取消了,微软已经创建了一些tools and guidelines。
部分信息为covered here too。您可能还想查找WeakReference作为替代方案。
请注意,COM和.NET不能很好地协调,但它们确实在谈论。一个很好的参考是由Don Box,SAMS Publishing提供的 .NET和COM完整互操作性指南。
<强> 编辑: 强>
回答你的“内存泄漏”问题:无法判断你是否引入了内存泄漏,以及它有多大。这取决于您调用COM对象的频率。每个运行过程调用一次?别担心。在内循环中称它为百分之几?要非常小心。想知道吗?查找原始文档或源:如果它在被破坏时释放句柄,内存或其他资源,那么是的,你引入了泄漏。