34

在过去的两年里,我一直在自学 Excel VBA,我认为有时在代码段末尾处理变量是合适的。例如,我已经看到它在改编自Ron de Bruin 的用于将 Excel 转换为 HTML 的代码中完成

Function SaveContentToHTML (Rng as Range)

        Dim FileForHTMLStorage As Object
        Dim TextStreamOfHTML As Object
        Dim TemporaryFileLocation As String
        Dim TemporaryWorkbook As Workbook

...

        TemporaryWorkbook.Close savechanges:=False
        Kill TemporaryFileLocation
        Set TextStreamOfHTML = Nothing
        Set FileForHTMLStorage = Nothing
        Set TemporaryWorkbook = Nothing

End Function

我对此进行了一些搜索,发现除了如何去做之外几乎没有,并且在一个论坛中发布了一个声明,即不需要清除任何局部变量,因为它们不再存在于End Sub. 我猜测,根据上面的代码,这可能不是真的End Function,或者在我没有遇到的其他情况下。

所以我的问题归结为:

  • 网络上是否有地方解释了变量清理的时间和原因,而我只是没有找到它?

如果没有人可以在这里解释...

  • 什么时候需要对 Excel VBA 进行变量清理,什么时候不需要?
  • 更具体地说...是否有特定的变量使用(公共变量?函数定义的变量?)在内存中的加载时间比 subs 更长,因此如果我自己不清理可能会造成麻烦?
4

3 回答 3

63

VB6/VBA 使用确定性方法来破坏对象。每个对象存储对其自身的引用数。当数字达到零时,对象被销毁。

对象变量保证Nothing在它们超出范围时被清除(设置为),这会减少它们各自对象中的引用计数器。无需手动操作。

只有两种情况需要显式清理:

  1. 当您希望在其变量超出范围之前销毁对象(例如,您的过程将需要很长时间才能执行,并且该对象拥有资源,因此您希望尽快销毁该对象以释放资源)。

  2. 当您在两个或多个对象之间有循环引用时。

    如果objectA存储对 的引用objectBobjectB存储对 的引用,则这两个对象将永远不会被销毁,除非您通过显式设置或objectA来中断链。objectA.ReferenceToB = NothingobjectB.ReferenceToA = Nothing

您显示的代码片段是错误的。无需手动清理。进行手动清理甚至是有害的,因为它会给您一种更正确代码的错误感觉

如果您在类级别有一个变量,那么当类实例被破坏时,它将被清除/销毁。如果你愿意,你可以提前销毁它(参见 item 1.)。

如果您在模块级别有一个变量,它将在您的程序退出时被清理/销毁(或者,在 VBA 的情况下,当 VBA 项目被重置时)。如果你愿意,你可以提前销毁它(参见 item 1.)。

变量的访问级别(公共与私有)不影响其生命周期。

于 2013-09-26T21:18:57.487 回答
6

VBA 使用通过引用计数实现的垃圾收集器。

给定对象可以有多个引用(例如,Dim aw = ActiveWorkbook创建对 Active Workbook 的新引用),因此垃圾收集器仅在明确没有其他引用时才清理对象。设置为 Nothing 是减少引用计数的一种显式方式。当您退出范围时,计数会隐式递减。

严格来说,在现代 Excel 版本(2010+)中,没有必要设置为 Nothing,但旧版本的 Excel 存在问题(解决方法是显式设置)

于 2013-09-26T20:58:38.803 回答
1

我至少有一种情况,数据没有自动清理,这最终会导致“内存不足”错误。在用户表单中,我有:

Public mainPicture As StdPicture
...
mainPicture = LoadPicture(PAGE_FILE)

当 UserForm 被销毁(之后Unload Me)时,为加载的数据分配的内存mainPicture没有被取消分配。我不得不添加一个明确的

mainPicture = Nothing

在终止事件中。

于 2018-09-28T13:06:29.397 回答