VBA Garbage collection: is memory of Global variables released when the excel application closes without a reset? - vba

Global variables are modular-level objects and retain assignments after procedures run, however, if excel is closed without resetting END, does the lifespan of a global persist in memory until a future time it is declared or invoked?
Needing to make explicitly clear in my mind this is a FALSE claim.
Release/free vs Purge Global/Public Variables from memory - Excel VBA was a helpful article, but am seeing some strange results possibly contradicting my belief.

Related

Difference between a constant and variable member in compiled or interpreted code

For a while now I have been a little confused about the role of constant members within a language, such as Java or C. I understand that at the source code level, they prevent certain critical members from being mutated and changed, but when compiled or interpreted, is there any difference between them and variable members at all or are they all just pointers to memory addresses?
I thought that perhaps the compiler/interpreter has to implement something special to allow a variable to be mutable, something it wouldn't have to when handling a constant member (perhaps making execution faster or making it use less memory?), is this true or am I completely up the wrong tree?
The const variable and the variable are not stored in the same place once your code is executed. The constant values will go in the flash memory with your program. The variables will go in the flash too but will then be copied in the ram to be modified as your program runs. Making a variable const makes your computer save time and space by not pushing everything in the ram. When you need to modify it, you will push it into the Ram anyway, but most of the time const variables will not be modified.
This is in addition to the software fact that you might want to prevent your code to modify a value by mistake.

OOP - Memory Usage and Large Math Objects (Classes)

I am starting to move many large non-OOP subroutines that involve expensive iterative math routines into their own class. Whenever I want to use one of the larger subroutines (which are now classes) I create them as an object, assuming that once the object is no longer used (since the calling code is exited) they will be removed form memory.
My question is: If an object is instantiated using say a button or triggering subroutine and the code in that routine is run, will that object get killed from memory via garbage collection once the code is completed?
Also, I don't want to multithread since the user won't be running more than one class at a time.
will that object get killed from memory via garbage collection once the code is completed?
No, not necessarily.
As soon as that code completes, there will be no more active references to the object. That means that it will then be eligible for garbage collection, but this doesn't happen immediately. It will get collected at some appropriate time after that point.

Forcing Garbage Collection

Is there a way to force garbage collection in VBA/Excel 2000?
This question refers to the Macro language in Excel.
Not using VB .NET to manipulate Excel. So GC.collect() won't work
You cannot take advantage of garbage collection provided by the .NET Framework when using straight VBA. Perhaps this article by Eric Lippert will be helpful
You can't force GC in VBA, but it's good to set to Nothing the global variables.
The article mentioned by kd7 says it's useless to set to Nothing the local variables before they go out of scope, but doesn't talk about the global variables.
In VBA the global variables defined in a module remain alive through the whole Excel session, i.e. until the document containing the VBA module that defines them closed.
So don't put useless Set O = Nothing when O is local, but do it when it's global.
VBA/Excel does not have garbage collection, like old VB. Instead of GC, it uses reference counting. Memory is freed when you set a pointer to nothing (or when variable goes out of scope). Like in old VB it means that circular references are never freed.

Is object clearing/array deallocation really necessary in VB6/VBA (Pros/Cons?)

A lot of what I have learned about VB I learned from using Static Code Analysis (Particularly Aivosto's Project Analyzer). And one one of things it checks for is whether or not you cleared all objects and arrays. I used to just do this blindly because PA said so. But now that I know a little bit more about the way VB releases resources, it seems to me that these things should be happening automatically. Is this a legacy feature from pre VB6, or is there a reason why you should explicitly set objects back to nothing and use Erase on arrays?
Matt Curland, author of Advanced Visual Basic 6, who knows more about Visual Basic than most of us ever will, thinks it is wasted effort. Consider this quote (p110) about DAO, the COM data access library that primarily targets the Access Database Engine:
another example of poor teardown code.
DAO has Close methods that must be
called in the correct order, and the
objects must be released in the
correct order as well (Recordset
before Database, for example). This
single poor object model behavior has
led to the misconception that VB leaks
memory unless you explicitly set all
the local variables to nothing at the
end of a function. This is a
completely false notion in a
well-designed object model. VB can
clear the variables faster at the End
Sub line than you can from code, and
it checks the variables even if you
explicitly release your references.
Any effort you make is duplicated.
The problem, as I understand it, has to do with the fact that VB6 (and its predecessors) has its roots in COM, and its reference-counting garbage collection system.
Imagine, for instance, that you declare a refernece to an object from a 3rd party library. That object has a COM reference count that is used both to keep it alive and to determine when it should be destroyed. It isn't destroyed when you set it to Nothing, but when the object's reference count reaches zero.
Now, not all COM components were written in Visual Basic. Some were written in C or C++. Structured exception handling didn't exist across all languages. So if an error occurred, the reference count on the object was not guaranteed to be properly reduced, and COM objects were known to hang around longer than they were intended to. This wasn't a problem with Visual Basic, per se. It was a COM problem. (And that, you might note, is why .NET doesn't use reference counting.)
That's why Visual Basic developers became obsessive about releasing object references prior to exiting routines. You simply don't know what a component you're allocating is creating under the hood. But when you release your reference to it, you're at least releasing your reference count to it. It became almost a religious mantra. Declare, use, release. It was the COM way of doing things.
Sure, Visual Basic might be better or faster at dereferencing variables I declared on the stack. But dammit, I want it to be OBVIOUS that those objects were released. A little assurance goes a long way when you're trying to track down a memory leak.
Have you read this Aivosto web page (from the creators of Project Analyzer)?
If you are using static variables,
it's important to reclaim the memory
they occupied when you don't need the
variables any more. With dynamic
variables memory isn't so much of a
problem, because they are destroyed
when the procedure ends.
In other words, you don't need to worry about clearing ordinary, non-static, local variables.
I always do it for good practice, you never know what an exception might do if you fall in one and your objects are not deallocated. You should relase them in finally statements and ensure they are not using any memory otherwise you may run into a memory leak.
I had an issue inside of a simple time off tracker system where the server kept on crashing randomly, it took weeks to determine it was a memory leak of an object that was supposed to self destruct on its own. My code was being thrown into an exception and never cleaned up after itself causing the server (the actual web site not the entire server) to go down.
Yes, set all objects to Nothing and clean up as much as you can. VB6 is notorious for having memory leaks when not cleaning up your stuff. Garbage collection was sub-par in VB6/VBA.

Is there a need to set Objects to Nothing

I always read that it is recommended to set objects to nothing, once I am done with them. But I normally use them only in functions inside forms.
Isn't the reference lost and memory released when the function scope is left, regardless of setting objects to Nothing?
i.e. is it really necessary to do:
Set db = Nothing
Set record_set = Nothing
VB uses a so-called "reference counting" garbage collector.
Basically, the moment a variable goes out of scope, the reference counter on the referenced object is decremented. When you assign the object reference to another variable, the reference counter is incremented.
When the counter reaches zero, the object is ready for garbage collection. The object resources will be released as soon as this happens. A function local variable will most likely reference an object whose reference count never goes higher than 1, so object resources will be released when the function ends.
Setting a variable to Nothing is the way to decrease the the reference counter explicitly.
For example, you read in a file, and set the file object variable to Nothing right after the ReadAll() call. The file handle will be released immediately, you can take your time process its contents.
If you don't set to Nothing, the file handle might be open longer than absolutely necessary.
If you are not in a "must unblock valuable resource" kind of situation, simply letting the variables go out of scope is okay.
Garbage collection is rarely perfect. Even in .NET there are times where you are strongly encouraged to prompt the system to do garbage collection early.
For this reason, I explicitly both close and set to Nothing recordsets when I'm done with them.
The very last line of the help topic for "Recordset.Close" in the Microsoft DAO help and the Access Developer Reference is this:
"An alternative to the Close method is
to set the value of an object variable
to Nothing (Set dbsTemp = Nothing)."
http://msdn.microsoft.com/en-us/library/bb243098.aspx
With that in mind, this article from the Microsoft Knowledge Base entitled "How to prevent database bloat after you use Data Access Objects (DAO)", tells you that you should explicitly close if you don't want your databases to bloat. You'll notice that the article is a little vague about the details; the "Cause" section is unclear, almost to the point of being gibberish.
http://support.microsoft.com/kb/289562
SYMPTOMS: A Microsoft Access database
has begun to bloat (or grow rapidly in
size) after you implement Data Access
Objects (DAO) to open a recordset.
CAUSE: If you do not release a
recordset's memory each time that you
loop through the recordset code, DAO
may recompile, using more memory and
increasing the size of the database.
MORE INFORMATION: When you create a
Recordset (or a QueryDef) object in
code, explicitly close the object when
you are finished. Microsoft Access
automatically closes Recordset and
QueryDef objects under most
circumstances. However, if you
explicitly close the object in your
code, you can avoid occasional
instances when the object remains
open.
Finally, let me add that I have been working with Access databases for 15 years, and I almost always let my locally declared recordset variables go out of scope without explicitly using the Close method. I have not done any testing on it, but it does not seem to matter.
When you are using ASP classic (server-side scripting), it is important to set all objects to nothing when you are through with them, because they do not go out of scope until the [virtual] server is shut down.
For this reason, all MS VB scripting examples always showed objects being closed and set to nothing. So that the script excerpts could be used in environments like ASP classic where the objects did not go out of scope.
There are, rarely, other situations where you wish to code long-running processes where the objects do not go out of scope, and you find yourself running out of physical memory if you do not explicitly release objects.
If you find yourself coding ASP classic, or running processes in global scope for some other reason, then yes, you should explicitly release objects.
References are supposed to be cleaned up when the variable goes out of scope. Presumably this has improved with later versions of the software, but it was at one time not reliable. I believe that it remains a good practice to explicitly set variables to "Nothing."
I usually always put this at the end of my procedures, or call a "CloseRecordSet" sub with it in if I'm using module level ones:
Private Sub Rawr()
On Error GoTo ErrorHandler
'Procedural Code Here.
ExitPoint:
'Closes and Destroys RecordSet Objects.
If Not Recset Is Nothing Then
If Recset.State = 1 Then
Recset.Close
Conn.Close
End If
Set Recset = Nothing
Set Conn = Nothing
End If
Exit Sub
ErrorHandler:
'Error Handling / Reporting Here.
Resume ExitPoint
End Sub
That way however the procedure ends, (be it normally or due to an error) the objects are cleaned up and resources are free.
Doing it that way is quite safe in that it you can just slap it in and it will only do what is necessary in regards to closing, or destroying the recordset / connection object, incase it has already been closed (due to a runtime error or just closing it early as ya should, this just makes sure).
Its really not much hassle and its always best to clean up your objects when you're finished with them to free up resources immediately regardless of what happens in the program.
Try this
If Not IsEmpty(vMyVariant) Then
Erase vMyVariant
vMyVariant = Empty
End If