什么时候必须在VB6中将变量设置为“Nothing”?

时间:2008-08-27 14:54:52

标签: vb6 memory-leaks

在我的一个VB6表单中,我创建了几个其他Form对象并将它们存储在成员变量中。

Private m_frm1 as MyForm
Private m_frm2 as MyForm

// Later...
Set m_frm1 = New MyForm
Set m_frm2 = New MyForm

我注意到,只要创建并销毁此(父)表单,我就会泄漏内存。我是否有必要将这些成员变量分配到Nothing中的Form_Unload()

一般情况下,何时需要?

已解决:当我在相关表单上执行Unload时,而不是在我将表单设置为Nothing时,修复了此特定内存泄漏。我设法通过明确地将类模块的一些实例设置为Nothing来删除一些其他内存泄漏。

8 个答案:

答案 0 :(得分:8)

实际上,VB6就像C ++一样实现RAII,这意味着本地声明的引用会在块结束时自动设置为Nothing。同样,应该在执行Class_Terminate后自动重置成员类变量。但是,有几份报告说这是不可靠的。我不记得任何严格的测试,但最好手动重置成员变量。

答案 1 :(得分:8)

@Matt Dillard - 没有设置这些可以解决你的内存泄漏问题吗?

VB6没有正式的垃圾收集器,更像是@Konrad Rudolph所说的。

实际上,在我的表单上调用unload似乎是确保清理主表单并确保每个子表单清理其行为的最佳方法。

我用一个空白项目和两个空白表格测试了这个。

Private Sub Form_Load()
  Dim frm As Form2
  Set frm = New Form2
  frm.Show
  Set frm = Nothing
End Sub

运行后,两个表格都可见。将frm设置为空无一人......没有。

在settign frm为空之后,打开此表单的唯一句柄是通过引用。

Unload Forms(1)

我是否正确看到了问题?

  • 约什

答案 2 :(得分:4)

@马丁

  
    

VB6有一个“With / End With”语句,它与C#.NET中的Using()语句“相似”。当然,你拥有的全球性越少,对你来说就越好。

  

使用/ End With不像Using语句那样工作,它不会在语句的末尾“Dispose”。

使用/ End With VB 6中的工作就像在VB.Net中一样,它基本上是一种快捷方式对象属性/方法调用的方法。 e.g。

与客户合作   .FirstName =“John”   .LastName =“史密斯”

结束

答案 3 :(得分:4)

VB中的对象具有引用计数。这意味着对象会保留有多少其他对象变量对其进行引用的计数。当没有对该对象的引用时,该对象被垃圾收集(最终)。此过程是COM规范的一部分。

通常,当本地实例化的对象超出范围(即退出子)时,其引用计数减1,换句话说,引用该对象的变量被破坏。因此,在大多数情况下,您不需要在退出Sub时显式设置等于Nothing的对象。

在所有其他实例中,您必须将对象变量显式设置为Nothing,以减少其引用计数(减1)。将对象变量设置为Nothing不一定会破坏对象,必须将ALL引用设置为Nothing。使用递归数据结构时,这个问题会变得特别严重。

另一个问题是,在对象变量声明中使用New关键字。对象仅在首次使用时创建,而不是在使用New关键字的位置创建。在声明中使用New关键字将在每次引用计数变为零时首次使用时重新创建对象。因此,将对象设置为Nothing可能会破坏它,但如果再次引用,则会自动重新创建对象。理想情况下,您不应声明使用New关键字,而是使用不具有此复活行为的New运算符。

答案 4 :(得分:2)

严格地说,从来没有,但它给垃圾收集器一个强有力的提示来清理。

作为一项规则:每次使用您创建的对象时都会执行此操作。

答案 5 :(得分:2)

将VB6引用设置为Nothing会减少VB对该对象的拒绝计数。当且仅当计数为零时,对象才会被销毁。

不要以为只是因为你设置为Nothing就像在.NET中一样“垃圾收集”

VB6使用引用计数器。

我们鼓励您设置“Nothing”实例化对象,这些对象可以引用C / C ++代码和类似的东西。自从我接触VB6以来已经很长时间了,但我记得将文件和资源设置为空。

在任何一种情况下它都不会受到伤害(如果它已经没有了),但这并不意味着该对象将被销毁。

VB6有一个“With / End With”语句,它与C#.NET中的Using()语句“相似”。当然,你拥有的全球性越少,对你来说就越好。

请记住,在任何一种情况下,有时创建一个大对象比保持一个引用存活并重用它更昂贵。

答案 6 :(得分:2)

我有一个类似于此的问题。我似乎认为它也会阻止应用关闭,但它可能适用于此。

我提取了旧代码,它看起来像是:

Dim y As Long
For y = 0 To Forms.Count -1
    Unload Forms(x)
Next

卸载m_frm1可能更安全。而不只是把它设置为空。

答案 7 :(得分:2)

这里尚未提到的一个重点是,如果没有对该对象的其他引用,将对象引用设置为Nothing将导致对象的析构函数运行(如果类是用VB编写的,则为Class_Terminate) count为零)。

在某些情况下,特别是在使用RAII模式时,终止代码可以执行可能引发错误的代码。我相信一些ADODB类就是这种情况。另一个例子是封装文件i / o的类 - 如果文件仍然打开,Class_Terminate中的代码可能会尝试刷新并关闭文件,这可能会引发错误。

因此,重要的是要注意设置对Nothing的对象引用会引发错误,并相应地处理它(确切地说将取决于您的应用程序 - 例如,您可以通过插入“On Error Resume Next”来忽略此类错误就在“Set ... = Nothing”之前。)