2008-11-05 75 views
2

有没有这样的事情?VB6中的动态内存分配

我在谈论类似于C++ new命令的内容,即分配需要显式释放内存的内存(或风险内存泄漏)。

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

我们曾经担心在VB6中开发时的内存管理?

回答

7

就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 

然后是在父

Private WithEvents MyProxy As MyObjectProxy 

Private Sub Class_Initialize() 
    Set MyProxy = New MyObjectProxy 
End Sub 

然后安装称为代理的只读属性来定义一个私有变量并实现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程序员的祸根。

注:我是从源称这是代理,但由于安东尼的评论,我觉得这也符合调解模式的定义。它使用特定的VB6中心功能; Event API并不完全符合Mediator Pattern的精神。

另外还要认识到在.NET框架有等同VB6的事件API虽然它实现方式不同(代表等)

+0

这就是众所周知的中介模式,值得添加到这个答案的文本。 – AnthonyWJones 2008-11-06 10:20:43

3

我想说你永远不必担心内存管理,但这不是真的。它在一定程度上取决于你的VB6代码运行的执行环境。当然,我已经看到了在COM +下运行的VB6类,如果它们完成时没有显式地将对象引用设置为Nothing,将会泄漏内存。

除了环境问题外,您在VB6类型系统中分配的内存通常会为您清理。我正在谈论您使用New关键字分配的内容。但有一个重要的例外,由rpetrich和其他人指出: -

由于VB用于管理分配对象的生存期的引用计数机制,如果您有任何循环引用,则可能会泄漏内存。例如,A-> B-> C-> A。如果你有这种情况,你可能需要自己发现它,并通过明确地将引用设置为Nothing来治愈它。我没有意识到任何有助于识别这类问题的工具。

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

因此,有没有规律可循,除非是: -

  1. 尝试尽可能多地了解你使用任何图书馆的行为,并
  2. 始终运行你的代码,而观看存储在性能监视器中进行跟踪以确保其内存使用量不会以无限制的方式增长。
  3. 尝试了解循环引用;-)
+0

由于VB6(和COM通常)使用参考计数,所以能够泄漏经由圆形物体引用。你应该编辑你的第二段来反映这 – rpetrich 2008-11-05 18:15:03

3

是的,我曾与各种形式的simmilar的问题,所以我将它们明确不了了之每个卸载。

但主要与第三方控件的问题似乎有时不是所有的COM引用在正确清除。

看一看here