有这样的事吗?
我说的是类似于 C++new
命令的东西,即需要显式释放内存(或有内存泄漏风险)的内存分配。
我问是因为我记得以前必须通过将表单/控件/其他对象设置为来解决一些 GDI 泄漏问题,Nothing
但现在不记得是什么或为什么......
在 VB6 中开发时,我们是否需要担心内存管理?
有这样的事吗?
我说的是类似于 C++new
命令的东西,即需要显式释放内存(或有内存泄漏风险)的内存分配。
我问是因为我记得以前必须通过将表单/控件/其他对象设置为来解决一些 GDI 泄漏问题,Nothing
但现在不记得是什么或为什么......
在 VB6 中开发时,我们是否需要担心内存管理?
就 VB6 中的内存管理而言,有几个方面值得关注。
第一个是循环引用,其中子类指向父类,反之亦然。在没有明确设置对 Nothing 的引用的情况下,有时表单也是如此,尤其是作为 Target 对象的编辑器的对话框。再次确保一切设置为空将解决问题。
基本原则是 1) 如果一个对象指向的任何东西都是“活着的”,那么它就不会被垃圾收集。因此,当您设置对循环引用的父对象的引用时,子对象还活着,因此父对象不会被垃圾收集,因为父对象还活着,孩子不会被垃圾收集。
表格也是一样。如果您没有将编辑对象的对话框的目标属性设置为空,那么只要目标对象处于活动状态,它就不会触发最后的一系列事件。
这样做最常见的副作用是您的应用程序无法正常关闭,并且您的内存占用量会随着应用程序的使用时间增加而增长。
至于 GDI 泄漏,只要您使用使用句柄、指针的外部 DLL。对于这些功能,您将自己置于与 C++ 相同的领域。因此,您必须确保遵循您正在使用的特定 API 或 DLL 的所有规则,这通常涉及在完成后显式销毁您创建的内容。
循环引用问题有一个优雅的解决方案。您使用代理而不是直接引用父母的孩子。
首先为父对象创建一个代理类。
Option Explicit Public Event GetRef(ByRef RHS As MyObject)
Public Function GetMyObject() As MyObject
Dim Ref As MyObject
RaiseEvent GetRef(Ref)
Set GetMyObject = Ref
End Function
然后在Parent中定义一个私有变量
Private WithEvents MyProxy As MyObjectProxy
Private Sub Class_Initialize()
Set MyProxy = New MyObjectProxy
End Sub
然后设置一个名为 Proxy 的只读属性并实现 GetRef 事件。
Public Property Get Proxy() As MyObjectProxy
Set Proxy = MyProxy
End Property
Private Sub MyProxy_GetRef(RHS As MyObject)
Set RHS = Me
End Sub
对于孩子或其他任何需要参考的东西,代码如下。
Private ParentProxy As MyObjectProxy
Public Property Get Parent() As MyObject
If ParentProxy Is Nothing Then
Set Parent = Nothing
Else
Set Parent = ParentProxy.GetRef
End If
End Property
Public Property Set Parent(RHS As MyObject)
If RHS Is Me Then
Set MyObjectProxy = Nothing
ElseIf Target Is Nothing Then
Set MyObjectProxy = Nothing
Else
Set MyObjectProxy = RHS.Proxy
End If
End Property
因为事件机制不设置引用或增加任一对象上的 COM 引用计数,它避免了整个循环引用问题,这是许多 VB6 程序员的祸根。
注意:我得到它的来源称它为代理,但感谢 Anthony 的评论,我发现它也符合中介者模式的定义。它使用特定的 VB6 Centric 功能;事件 API 不太符合中介者模式的精神。
还要意识到 .NET 框架与 VB6 的事件 API 等效,尽管它的实现方式不同(委托等)
我想说你永远不必担心内存管理,但这并不完全正确。这在一定程度上取决于运行 VB6 代码的执行环境。我当然见过在 COM+ 下运行的 VB6 类,如果它们在完成后没有明确地将对象引用设置为 Nothing,则会泄漏内存。
抛开环境问题不谈,您在 VB6 类型系统中分配的内存通常会为您清理干净。我说的是你用 New 关键字分配的东西。但 rpetrich 和其他人指出,有一个明显的例外:-
由于 VB 使用引用计数机制来管理已分配对象的生命周期,如果您有任何循环引用,则可能会泄漏内存。例如,A->B->C->A。如果您遇到这种情况,您可能需要自己发现它并通过显式设置对 Nothing 的引用来解决它。我不知道有任何工具对识别此类问题有很大帮助。
当您使用以其他语言编写的库时,会出现更多问题。您可能会新建一个用 C++ 编写的 COM 对象,该对象在内部分配一些内存,并发现您必须调用特定方法(例如 Close)来释放该内存。也许这样的 COM 对象写得不好,但它们中的很多都是存在的。
所以没有规则可以遵循,除了也许: -