什么时候必须在VB6中将变量设置为"无"?

时间:2020-03-05 18:43:55  来源:igfitidea点击:

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

Private m_frm1 as MyForm
Private m_frm2 as MyForm

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

我注意到,每当创建(销毁)该(父)表单时,我都会泄漏内存。我是否有必要将这些成员变量分配给Form_Unload()中的Nothing?

通常,什么时候需要?

已解决:当我在有问题的表单上执行"卸载"时,而不是在将表单设置为"无"时,这种特殊的内存泄漏已得到修复。通过将类模块的某些实例显式设置为" Nothing",我设法消除了一些其他的内存泄漏。

解决方案

回答

严格说来永远不会,但是它为垃圾收集器提供了清理工作的强大提示。

通常,每次完成对已创建对象的操作时,都应执行此操作。

回答

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

不要以为仅仅因为设置为Nothing就可以像在.NET中那样"收集垃圾"

VB6使用一个参考计数器。

鼓励我们将引用C / C ++代码和类似内容的实例化对象设置为" Nothing"。自接触VB6以来已经有很长时间了,但是我记得没有将文件和资源设置为空。

无论哪种情况,它都不会造成伤害(如果还没有的话),但这并不意味着该物体将被销毁。

VB6有一个" With / End With"语句,其工作方式类似于C#.NET中的Using()语句。当然,拥有的东西越少,对我们越有利。

请记住,无论哪种情况,有时创建大型对象都比使引用保持活动状态并重用它要昂贵得多。

回答

不久前,我遇到了类似的问题。我似乎认为这也会阻止该应用关闭,但在这里可能适用。

我拉起旧代码,它看起来像:

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

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

回答

@马丁

VB6 had a "With/End With" statement that worked "like" the Using() statement in C#.NET. And of course, the less global things you have, the better for you.

With / End With不能像Using语句那样工作,它不会在语句末尾"处分"。

With / End With在VB 6中的工作方式与在VB.Net中一样,基本上是一种用于快捷方式调用对象属性/方法的方法。例如

与客户
.FirstName ="约翰"
.LastName ="史密斯"
结束

回答

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

回答

@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设置为空无一事。

将frtign设置为空后,打开此表单的唯一句柄是通过引用。

Unload Forms(1)

我可以正确看到问题了吗?

  • 乔希

回答

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

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

在所有其他情况下,必须将对象变量显式设置为Nothing,以减少其引用计数(减1)。将对象变量设置为Nothing,不一定会破坏对象,必须将ALL引用设置为Nothing。对于递归数据结构,此问题可能变得尤为严重。

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

回答

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

在某些情况下,尤其是在使用RAII模式时,终止代码可以执行可能引起错误的代码。我相信某些ADODB类就是这种情况。另一个示例是一个类,它封装文件I / O,如果Class_Terminate中的代码仍处于打开状态,则该代码可能会尝试刷新并关闭该文件,这可能会引发错误。

因此,请务必注意,将对象引用设置为Nothing会引发错误,并相应地进行处理(确切地说,这将取决于应用程序,例如,我们可以通过在"设置... =没事")。