10

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

Private m_frm1 as MyForm
Private m_frm2 as MyForm

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

我注意到每当创建和销毁此(父)表单时,我都会泄漏内存。我有必要将这些成员变量分配给NothinginForm_Unload()吗?

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

已解决:当我对有Unload问题的表单执行操作时,而不是当我将表单设置为Nothing. 我还通过将一些类模块的实例显式设置为 ,设法消除了其他一些内存泄漏Nothing

4

8 回答 8

9

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

于 2008-08-27T15:27:05.903 回答
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 设置为 nothing 效果很好……没有。

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

Unload Forms(1)

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

  • 乔什
于 2008-08-27T17:23:30.600 回答
5

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

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

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

Another gotcha, is when using the New keyword in an object variable declaration. An object is only created on first use, not at the point where the New keyword is used. Using the New keyword in the declaration will re-create the object on first use every time its reference count goes to zero. So setting an object to Nothing may destroy it, but the object will automatically be recreated if referenced again. Ideally you should not declare using the New keyword, but by using the New operator which doesn't have this resurrection behaviour.

于 2008-09-29T11:31:28.077 回答
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
于 2008-08-27T15:11:41.993 回答
2

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

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

于 2008-08-27T15:05:45.830 回答
2

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

不要认为仅仅因为您设置为 Nothing 它会像在 .NET 中那样被“垃圾收集”

VB6 使用引用计数器。

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

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

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

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

于 2008-08-27T15:07:40.707 回答
2

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

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

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

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

于 2008-08-27T15:07:44.703 回答
2

One important point that hasn't yet been mentioned here is that setting an object reference to Nothing will cause the object's destructor to run (Class_Terminate if the class was written in VB) if there are no other references to the object (reference count is zero).

In some cases, especially when using a RAII pattern, the termination code can execute code that can raise an error. I believe this is the case with some of the ADODB classes. Another example is a class that encapsulates file i/o - the code in Class_Terminate might attempt to flush and close the file if it's still open, which can raise an error.

So it's important to be aware that setting an object reference to Nothing can raise an error, and deal with it accordingly (exactly how will depend on your application - for example you might ignore such errors by inserting "On Error Resume Next" just before "Set ... = Nothing").

于 2009-07-22T06:47:54.350 回答