VBA对象销毁 - 内存错误

时间:2014-08-25 02:06:20

标签: excel vba class excel-vba

我创建了一个类对象,引用了其他类(其他类都没有引用)。我有一个内存问题,导致内存不足'循环并创建类的实例时出错。类和子例程的简化代码片段如下:

Class aclsWell

Option Explicit
Option Compare Text
Option Base 1

Private zclsSettings As bclsSettings
Private zclsInfo As bclsInfo
Private zclsProduction As bclsProduction

Private Sub Class_Initialize()
 Set zclsSettings = New bclsSettings: Set zclsSettings.Parent = Me
 Set zclsInfo = New bclsInfo: Set zclsInfo.Parent = Me
 Set zclsProduction = New bclsProduction: Set zclsProduction.Parent = Me
End Sub

Private Sub Class_Terminate()
 Set zclsSettings.Parent = Nothing: Set zclsSettings = Nothing
 Set zclsInfo.Parent = Nothing: Set zclsInfo = Nothing
 Set zclsProduction.Parent = Nothing: Set zclsProduction = Nothing
End Sub

模块:

Sub Test1()

Dim zwell As aclsWell

For i = 1 To 2000
    Set zwell = New aclsWell
    Set zWell = Nothing
Next i

End sub

完成Test1后,excel正在使用大约1 GB的数据,如果再次运行,我会收到错误消息。但是,如果我按下VBA窗口中的停止按钮,内存将清除。有没有办法模仿使用VBA命中停止按钮(如Application.stopmacro或类似的东西)。或者我在关闭对象的方式中有一个基本问题?非常感谢任何见解。

2 个答案:

答案 0 :(得分:4)

当你有双向参考时,这很棘手。您的终止事件永远不会触发,因为当您将对象设置为Nothing时,引用计数不为零。因此,您无法在终止事件中清理您的引用。

一种选择是创建自己的终止方法。

Public Sub Terminate()
 Set zclsSettings.Parent = Nothing: Set zclsSettings = Nothing
 Set zclsInfo.Parent = Nothing: Set zclsInfo = Nothing
 Set zclsProduction.Parent = Nothing: Set zclsProduction = Nothing

End Sub

Sub Test1()

Dim zwell As aclsWell
Dim i As Long

For i = 1 To 2000
    Set zwell = New aclsWell
    zwell.Terminate
    Set zwell = Nothing
Next i

End Sub

现在当你单步执行代码时,你的Class_Terminate事件将会触发,因为Terminate方法将引用计数降为零,VBA知道它可以清理对象。

我使用的方法是将父节点的内存位置存储在子节点中,并存储为Long(或64位的LongPtr)。 Read this post,尤其是Rob Bruce在评论部分的评论。

' In your child class
Private m_lngParentPtr As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
                               (dest As Any, Source As Any, ByVal bytes As Long)

' The Parent property
Public Property Get Parent() As Class1
    Set Parent = ObjFromPtr(m_lngParentPtr)
End Property
Public Property Set Parent(obj As Class1)
    m_lngParentPtr = ObjPtr(obj)
End Property

'Returns an object given its pointer.
'This function reverses the effect of the ObjPtr function.
Private Function ObjFromPtr(ByVal pObj As Long) As Object
    Dim obj                     As Object
    ' force the value of the pointer into the temporary object variable
    CopyMemory obj, pObj, 4
    ' assign to the result (this increments the ref counter)
    Set ObjFromPtr = obj
    ' manually destroy the temporary object variable
    ' (if you omit this step you’ll get a GPF!)
    CopyMemory obj, 0&, 4
End Function

答案 1 :(得分:2)

尝试使用End关键字

Sub Test1()

Dim zwell As aclsWell

For i = 1 To 2000
Set zwell = New aclsWell
Set zWell = Nothing

Next i
End
End sub