在我的一个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
来删除一些其他内存泄漏。
答案 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”之前。)