I haven't fully followed this thread so apologies in advance if I've missed
something, however I don't follow how this example relates to Isabelle's
wanting to explicitly destroy worksheet references.
The memory occupied by an object variable is trivial and very unlikely ever
to be noticed, it's only a pointer to the handle of an object. In the case
of a worksheet reference, even if global and not destroyed when say the
worksheet is deleted, no harm will be done (albeit bad practice for other
reasons). It will simply store a number, the old pointer to the worksheet.
That said, if the reference was to a sheet in an automated instance, failure
to release could leave the Excel instance hanging in memory.
In your example you created an object, and as a COM object (an instance of
the Class) it will 'stay alive' until the last reference to it is released
(explicitly or goes out of scope), then the object will destroy itself. Sure
the memory the object occupies (not the reference to it) while alive is
relative to the class, its methods etc, and not least allocation for any
declared variables.
FWIW issues can arise with classes and circular references (classes refer to
each other), then they can be difficult if not impossible to tear down and
release memory, but that's a different matter.
Regards,
Peter T
I do not notice any such memory leak in XL2003 SP3 with
VBA 6.5.1024.
Here is a better demonstration. Again, I must rely on Task Manager to
monitor process memory usage.
Copy the class object below into a class module names myTest1. Note
that all it does is allocate 1 MB of memory.
Copy the macros below into a regular module. Follow the instructions
at the top.
My observations (YMMV).... When I run testit1st, I get the following
results:
Mem Usage VM Size
18968 7680 before Set=New
20016 8712 global Set=New
21044 9740 local Set=New
20020 8712 exit testit2; local object freed
20020 8712 end testit1st; global object remains
Interpretation.... Local object memory is freed automatically when
the procedure exits; Set=Nothing is not needed. This is the situation
in Isabelle's example.
Global object memory is not free when the procedure exits. That's to
be expected, and it may be desired since often we want values of
global variables to persist between calls. Of course, if not desired,
we must do Set=Nothing. But that is not the situation in Isabelle's
example.
Note: Minor differences of a page or two (4K per page) probably
reflects Excel or VBA memory usage, e.g. for MsgBox, not a leak. The
key difference to look for is 1000K (1 MB), which reflects the
allocation of the class object.
When I run testit2nd, I get the following results:
Mem Usage VM Size
20040 8716 previous global Set=New
20040 8716 new global Set=New
Interpretation.... Set=New to an object variable that references
object memory causes the original reference count to be decremented,
and the original memory to be freed if the reference count goes to
zero. Thus, the new object allocation "replaces" the old object
allocation; Set=Nothing is not needed.
-----
class module myTest1:
Private xArr(1 To 1024 * 1024&) As Byte
-----
regular module:
'****************************************
'start Task Manager
'select Excel process in Processes tab
'scroll Excel process to the top
'position TM window low and to the side
' so that Excel MsgBox can be seen
'run testit1st
'then run testit2nd
'****************************************
Dim a As myTest1
Sub testit1st()
Dim s As String
'*** be sure no memory is in-use
Set a = Nothing
checkit "record"
'*** allocate memory
Set a = New myTest1
checkit "increase"
'*** demonstrate that testit2 exit
'*** frees memory for its myTest1 object
testit2
checkit "decrease"
'*** demonstrate that global myTest1 object
'*** remains in-use after test1 exits
checkit "unchanged later", False
End Sub
Sub testit2nd()
Dim s As String
'*** demonstrate that memory is replaced
'*** (probably freed, then re-allocated)
'*** when re-Set'g New object variable
checkit "record"
Set a = New myTest1
checkit "unchanged"
End Sub
Private Sub testit2()
Dim a As myTest1
Set a = New myTest1
checkit "increase"
If setNothing Then Set a = Nothing
End Sub
Private Sub checkit(tag As String, _
Optional doWait As Boolean = True)
If doWait Then
'*** time for Task Manager to change
Application.Wait Now() + TimeSerial(0, 0, 3)
End If
MsgBox tag
End Sub