views:

3077

answers:

12

In one of my VB6 forms, I create several other Form objects and store them in member variables.

Private m_frm1 as MyForm
Private m_frm2 as MyForm

// Later...
Set m_frm1 = New MyForm
Set m_frm2 = New MyForm

I notice that I'm leaking memory whenever this (parent) form is created and destroyed. Is it necessary for me to assign these member variables to Nothing in Form_Unload()?

In general, when is that required?

SOLVED: This particular memory leak was fixed when I did an Unload on the forms in question, not when I set the form to Nothing. I managed to remove a few other memory leaks by explicitly setting some instances of Class Modules to Nothing, as well.

+3  A: 

Strictly speaking never, but it gives the garbage collector a strong hint to clean things up.

As a rule: do it every time you're done with an object that you've created.

Allain Lalonde
What garbage collector? VB 6 uses reference counting...
Pop Catalin
I know. I just meant "the thing that deallocates unused instances" Be it a separate process that does fancy stuff like aging, etc. It's still cleaning memory. Just really badly :)
Allain Lalonde
A: 

Setting a VB6 reference to Nothing, decreases the refecences count that VB has for that object. If and only if the count is zero, then the object will be destroyed.

Don't think that just because you set to Nothing it will be "garbage collected" like in .NET

VB6 uses a reference counter.

You are encouraged to set to "Nothing" instanciated objects that make referece to C/C++ code and stuff like that. It's been a long time since I touched VB6, but I remember setting files and resources to nothing.

In either case it won't hurt (if it was Nothing already), but that doesn't mean that the object will be destroyed.

VB6 had a "With/End With" statement that worked "like" the Using() statement in C#.NET. And of course, the less global things you have, the better for you.

Remember that, in either case, sometimes creating a large object is more expensive than keeping a reference alive and reusing it.

Martín Marconcini
+2  A: 

I had a problem similar to this a while back. I seem to think it would also prevent the app from closing, but it may be applicable here.

I pulled up the old code and it looks something like:

Dim y As Long
For y = 0 To Forms.Count -1
    Unload Forms(x)
Next

It may be safer to Unload the m_frm1. and not just set it to nothing.

Josh Miller
A: 

@allain

VB 6 Garbage Collector? Huh? :)

BZ
A: 

@BZ: well... VB6 "had" some internal garbage collector, but FAAAAAAAAR from what we know as a modern GC like the ones you can see in .NET, Java and even Objective-C 2.0.

Martín Marconcini
+3  A: 

@Martin

VB6 had a "With/End With" statement that worked "like" the Using() statement in C#.NET. And of course, the less global things you have, the better for you.

With/End With does not working like the Using statement, it doesn't "Dispose" at the end of the statement.

With/End With works in VB 6 just like it does in VB.Net, it is basically a way to shortcut object properties/methods call. e.g.

With aCustomer .FirstName = "John" .LastName = "Smith" End WIth

BZ
+4  A: 

Actually, VB6 implements RAII just like C++ meaning that locally declared references automatically get set to Nothing at the end of a block. Similarly, it should automatically reset member class variables after executing Class_Terminate. However, there have been several reports that this is not done reliably. I don't remember any rigorous test but it has always been best practice to reset member variables manually.

Konrad Rudolph
I suspect those rumors about it being unreliable were more likely a result of developers losing track of their references. I've been coding in VB6 for 10 years and the only time I've needed to explicitly needed to set an object to nothing is to prevent cycles.
Darrel Miller
+1  A: 

@BZ: you're totally right, With was just a shortcut.

it was a long time ago… ;)

Martín Marconcini
+3  A: 

@Matt Dillard - Did setting these to nothing fix your memory leak?

VB6 doesn't have a formal garbage collector, more along the lines of what @Konrad Rudolph said.

Actually calling unload on your forms seems to me to be the best way to ensure that the main form is cleaned up and that each subform cleans up their actions.

I tested this with a blank project and two blank forms.

Private Sub Form_Load()
  Dim frm As Form2
  Set frm = New Form2
  frm.Show
  Set frm = Nothing
End Sub

After running both forms are left visible. setting frm to nothing did well... nothing.

After settign frm to nothing, the only handle open to this form is via the reference.

Unload Forms(1)

Am I seeing the problem correctly?

  • Josh
Josh Miller
A: 

http://www.aivosto.com/vbtips/#memory

+2  A: 

Objects in VB have reference counting. This means that an object keeps a count of how many other object variables hold a reference to it. When there are no references to the object, the object is garbage collected (eventually). This process is part of the COM specification.

Usually, when a locally instantiated object goes out of scope (i.e. exits the sub), its reference count goes down by one, in other words the variable referencing the object is destroyed. So in most instances you won't need to explicitly set an object equal to Nothing on exiting a Sub.

In all other instances you must explicitly set an object variable to Nothing, in order to decrease its reference count (by one). Setting an object variable to Nothing, will not necessarily destroy the object, you must set ALL references to Nothing. This problem can become particularly acute with recursive data structures.

Another gotcha, is when using the New keyword in an object variable declaration. An object is only created on first use, not at the point where the New keyword is used. Using the New keyword in the declaration will re-create the object on first use every time its reference count goes to zero. So setting an object to Nothing may destroy it, but the object will automatically be recreated if referenced again. Ideally you should not declare using the New keyword, but by using the New operator which doesn't have this resurrection behaviour.

Jonathan Swift
+1  A: 

One important point that hasn't yet been mentioned here is that setting an object reference to Nothing will cause the object's destructor to run (Class_Terminate if the class was written in VB) if there are no other references to the object (reference count is zero).

In some cases, especially when using a RAII pattern, the termination code can execute code that can raise an error. I believe this is the case with some of the ADODB classes. Another example is a class that encapsulates file i/o - the code in Class_Terminate might attempt to flush and close the file if it's still open, which can raise an error.

So it's important to be aware that setting an object reference to Nothing can raise an error, and deal with it accordingly (exactly how will depend on your application - for example you might ignore such errors by inserting "On Error Resume Next" just before "Set ... = Nothing").

Joe