我啥时候必须在 VB6 中将变量设置为“无”?

Posted

技术标签:

【中文标题】我啥时候必须在 VB6 中将变量设置为“无”?【英文标题】:When must I set a variable to "Nothing" in VB6?我什么时候必须在 VB6 中将变量设置为“无”? 【发布时间】:2008-08-27 14:54:52 【问题描述】:

在我的一个 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吗?

一般来说,什么时候需要?

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

我怀疑那些关于它不可靠的谣言更可能是由于开发人员忘记了他们的参考资料。我已经在 VB6 中编码 10 年了,我唯一需要明确需要将对象设置为空的时候就是防止循环。【参考方案2】:

@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 设置为 nothing 效果很好……什么都没有。

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

Unload Forms(1)

我是否正确地看到了问题?

乔什

【讨论】:

【参考方案3】:

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

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

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

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

【讨论】:

【参考方案4】:

@马丁

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

With/End With 不像 Using 语句那样工作,它不会在语句末尾“处理”。

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

With aCustomer
  .FirstName = "John"
  .LastName = "Smith"
End With

【讨论】:

【参考方案5】:

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

作为一项规则:每次完成您创建的对象时都这样做

【讨论】:

我知道。我的意思是“释放未使用实例的东西”是一个单独的进程,它会做一些花哨的事情,比如老化等。它仍在清理内存。真的很糟糕:) @AlllainLalonde:“严格来说”,它不是垃圾收集器,VB6 中也没有其他单独的进程。【参考方案6】:

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

不要以为设置为 Nothing 就会像 .NET 中那样被“垃圾收集”

VB6 使用引用计数器。

我们鼓励您将引用 C/C++ 代码和类似内容的实例化对象设置为“无”。很久没有接触VB6了,但我记得我把文件和资源都设置成了空。

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

VB6 有一个“With/End With”语句,其工作方式“类似于”C#.NET 中的 Using() 语句。当然,你拥有的全球性东西越少,对你来说就越好。

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

【讨论】:

C# 中的 Using 关键字不像 VB6 的 With 块。 Using 用于 IDisposable 实现,VB6 没有类似的功能。 正确,因此“喜欢”周围的“引号”。很像,但跟幕后的真实无关。【参考方案7】:

不久前我遇到了类似的问题。我似乎认为它也会阻止应用程序关闭,但它可能适用于此。

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

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

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

【讨论】:

【参考方案8】:

这里还没有提到的重要一点是,如果没有其他对对象的引用(参考计数为零)。

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

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

【讨论】:

以上是关于我啥时候必须在 VB6 中将变量设置为“无”?的主要内容,如果未能解决你的问题,请参考以下文章

我啥时候应该在 JavaScript 中使用 delete vs 将元素设置为 null? [复制]

VB6 如何在win7中将鼠标形状设置成手指形状?

我啥时候应该在我的响应标头中真正将“Access-Control-Allow-Credentials”设置为“true”?

我啥时候应该使用 GRUB_TIMEOUT 选项? [关闭]

我啥时候可以开始使用使用 UIAppearance 设置的属性?

如何在flutter中将token设置为全局变量?所以我可以随时随地访问令牌