2

有这样的事吗?

我说的是类似于 C++new命令的东西,即需要显式释放内存(或有内存泄漏风险)的内存分配。

我问是因为我记得以前必须通过将表单/控件/其他对象设置为来解决一些 GDI 泄漏问题,Nothing但现在不记得是什么或为什么......

在 VB6 中开发时,我们是否需要担心内存管理?

4

3 回答 3

8

就 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 等效,尽管它的实现方式不同(委托等)

于 2008-11-05T13:35:42.493 回答
3

我想说你永远不必担心内存管理,但这并不完全正确。这在一定程度上取决于运行 VB6 代码的执行环境。我当然见过在 COM+ 下运行的 VB6 类,如果它们在完成后没有明确地将对象引用设置为 Nothing,则会泄漏内存。

抛开环境问题不谈,您在 VB6 类型系统中分配的内存通常会为您清理干净。我说的是你用 New 关键字分配的东西。但 rpetrich 和其他人指出,有一个明显的例外:-

由于 VB 使用引用计数机制来管理已分配对象的生命周期,如果您有任何循环引用,则可能会泄漏内存。例如,A->B->C->A。如果您遇到这种情况,您可能需要自己发现它并通过显式设置对 Nothing 的引用来解决它。我不知道有任何工具对识别此类问题有很大帮助。

当您使用以其他语言编写的库时,会出现更多问题。您可能会新建一个用 C++ 编写的 COM 对象,该对象在内部分配一些内存,并发现您必须调用特定方法(例如 Close)来释放该内存。也许这样的 COM 对象写得不好,但它们中的很多都是存在的。

所以没有规则可以遵循,除了也许: -

  1. 尝试尽可能多地了解您使用的任何库的行为,并且
  2. 在性能监视器中查看内存跟踪的同时始终运行您的代码,以确保其内存使用量不会以无限制的方式增长。
  3. 尝试注意循环引用;-)
于 2008-11-05T08:26:55.207 回答
3

是的,我在各种形式上都遇到了类似的问题,所以我在每次卸载时都将它们明确设置为空。

但主要与 3rd 方控件有关的问题似乎有时并非所有 COM 引用都正确清除。

看看这里

于 2008-11-05T08:38:47.633 回答