关于内存泄漏:何时必须在VB6中将变量设置为“ Nothing”?

关于内存泄漏:何时必须在VB6中将变量设置为“ Nothing”?

When must I set a variable to “Nothing” in VB6?

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

1
2
3
4
5
6
Private m_frm1 as MyForm
Private m_frm2 as MyForm

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

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

通常,什么时候需要?

已解决:当我在有问题的表单上执行Unload时,而不是在将表单设置为Nothing时,解决了此特定的内存泄漏。 通过将类模块的某些实例显式设置为Nothing,我设法消除了一些其他的内存泄漏。


@Matt Dillard-设置这些为空不会解决内存泄漏问题吗?

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

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

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

1
2
3
4
5
6
Private Sub Form_Load()
  Dim frm As Form2
  Set frm = New Form2
  frm.Show
  Set frm = Nothing
End Sub

运行后,两种形式都可见。将frm设置为空无一事。

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

1
Unload Forms(1)

我能正确看到问题吗?

  • 乔希

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


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

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

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

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


@马丁

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中一样,基本上是一种用于快捷方式调用对象属性/方法的方法。例如

1
2
3
4
With aCustomer
  .FirstName ="John"
  .LastName ="Smith"
End With

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

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

因此,请务必注意,将对象引用设置为Nothing会引发错误,并相应地进行处理(确切地说,这将取决于您的应用程序-例如,您可能会在"设置... =否"。


我前一段时间有类似的问题。我似乎认为这也会阻止该应用关闭,但在这里可能适用。

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

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

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


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

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

VB6使用参考计数器。

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

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

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

请记住,无论哪种情况,有时创建大型对象都比保持引用有效并重用它昂贵。


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

通常,每次创建对象时都要这样做。


推荐阅读

    Python之可迭代对象、迭代器、生成器

    Python之可迭代对象、迭代器、生成器,迭代,生成器,一、概念描述可迭代对象就是可以迭代的对象,我们可以通过内置的iter函数获取其迭代器,可

    应用程序对象

    应用程序对象,,应用程序对象是一个应用程序级对象,用于在所有用户之间共享信息,并且在Web应用程序运行期间可以保存数据。 应用的性质: 方法

    为什么WPS表单总是不打开

    为什么WPS表单总是不打开,,为什么WPS表格总是打不开??百度知道为您找到了6条优质回答span>a,type:cluster">很有可能文件已经损坏。恢复

    laravel-admin|自定义表单与验证

    laravel-admin|自定义表单与验证,表单,场景,场景:很多时候,由于我们业务场景比较特殊,需要自定义表单,然后框架给我提供了对应表单组建!案列:以

    Java创建对象的几种方式

    Java创建对象的几种方式,对象,方法,本文目录Java创建对象的几种方式java中几种创建对象的方式1Java中创建对象的集中方式有那些JAVA创建对