Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Setting Object variable to nothing 5

Status
Not open for further replies.

pmcdaniel

Programmer
Feb 9, 2007
127
US
Curious question.....

Would it be more beneficial to set an object variable to Nothing and immediatly on the next line setting it again to another object or does this not make a difference as long as I set it to Nothing when finished?

I found a TON of object variables in an application I'm working on that are never set to Nothing and I'd like to start a clean-up process.

Also, if you don't mind - a quick explanation so I can use it when asked why I'm fixing all these object variables.

Thanks much
 
I don't know how everyone else feels, but I believe that code is cleaner doing this and it ensures the object is destroyed. It was taught to me that initialization and destruction of objects/memory were very important, and from what I understand are the reason for so many security flaws in software today.
 
With VB6 this shows that the programmer was "object-aware" more than anything: this isn't C++. You can reassign object references without setting them to Nothing because that's all they are: references. And objects that aren't set to Nothing are destroyed when they go out of scope, so even going back to do that is probably not a good use of time and might introduce bugs.
 
While I find your concern to be misplaced in this case, I'd like to say up front that also find it commendable. These are all good and intelligent questions.

<Would it be more beneficial to set an object variable to Nothing and immediatly on the next line setting it again to another object or does this not make a difference [etc]

As far as I'm concerned, this is analogous to first assigning the value of 0 to an integer every time you change its value. As harebrain says, an "object" variable is nothing more than a pointer.

<as long as I set it to Nothing when finished?
I agree with harebrain on this one. I wouldn't do it, and don't do it in practice. IMHO, all you're doing is adding unnecessary code overhead.

<a quick explanation so I can use it when asked why I'm fixing all these object variables.
My position is that if it ain't broke, don't fix it.

<It was taught to me that initialization and destruction of objects/memory were very important
I agree, and so do the developers of VB. That's why they took it upon themselves to do it. While one does hear sometimes about memory leaks in VB code, I've never seen one--the ones I've heard of had their source in a class instantiated by VB. It is most unlikely in my mind that specifically releasing the resources in VB code represents a cleaner model.

HTH

Bob
 
So what you're saying is that the 80-100 objects that are initialized but never destroyed are okay? I'm not talking about the ones that are re-used. BobRhodes explaination of reusing them makes sense. However, I can't see how setting them to nothing when done could cause bugs especially if they are in a procedure. In an entire module is of course a different matter and I know I'd have to be careful they aren't still being used in other places in the module.

This application runs by itself and I can say the longer it runs and generates reports the more likely something goes wrong. For instance it always crashes when doing one particular report where there are plenty of object variables being used.

I went through the code and discovered all these objects and forwarded a message to my superiors how it could be a huge improvement if we were to go and do what should have been done in the first place. I have been told though that "we don't have time" and "it won't make that big of a difference." I'm sure you've all heard the excuses before...... So am I wrong and we're not experiencing memory leaks due to non-destroyed object variables?

 
Whenever an object reference variable goes out of scope the reference is released, deallocating the object if no other references to it exist.

Explicitly setting a reference to Nothing is thus most valuable for global references. Even then the issue is usually about releasing unneeded resources early than it is anything functional.

Most object related "memory leaks" involve arrays or collections that may hold references for long periods of time, such as until program termination or library unloading. This is a good example of a place to set the references to Nothing unless you plan to deallocate the containing structure right away (Erase the array, set the collection to Nothing). The same can be said about VB control arrays, where you Unload instances to dispose of them - though most controls in control arrays can be reset and recycled.

Special cases exist for scenarios such as ASP pages and COM+ applications where some objects may be pooled. These systems try to re-use and redistribute a small set of instances of the actual objects they manage. Holding references to them for an extended period interferes with the goals of object pooling.

There are also circular reference scenarios to watch out for, where objects hold references to each other. Without care this can prevent anything in the circle from being deallocated as well as anything else these objects hold references to. Simply setting things to Nothing haphazardly won't help much though.

Then there is the [tt]Dim x As New Y[/tt] case to watch for. This confuses some programmers so badly they shun it, and tell others to as well even though it has perfectly good uses.

One of the silliest things I see is:
Code:
Set rs = New ADODB.Recordset
Set rs = conn.Execute(...)
This creates one Recordset and then turns around and throws it away, replacing it with a new one. Simply a waste of time and energy.
 
Worth pointing out that setting an Object to Nothing does NOT free up the object. All it does is decrement a reference count. Only when that reference count equals 0 is the object freed.
 
There are also issues with out-of-process servers.

You might release all references to some Class in an ActiveX EXE but leave it loaded forever if it has a Form (even a hidden one) loaded. You may need to call some sort of "Quit" method on it before releasing the reference.
 
Wow, I didn't realize this would go so far over my head. We've got a VB 6 app with many references to WORD and when one certain job runs we get a message about Word running out of memory. I've found countless(well maybe not that many) Word objects being built along with bookmarks which are never set to nothing so I assumed this is part of the problem. There are also over a hundred bookmarks on the document.....I didn't write this thing....I only investigated it and have been finding all this stuff.
 
I would suggest that you narrow down the place where you are running out of memory, with emphasis on the code that you and your company have created. For example, are you calling a Word macro from anywhere? It may well be that you can only have so many references to Word, and you may find that you have one too many references in scope at a given time.

So, let's take a step or two back. Do you understand when references to objects are released?
 
We do not use macros for this particular application. We use VBA code inside VB 6.

As far as I know the references to the objects are never released because they are never set to nothing. Where applicable they're never closed either.

The application runs automatically and has a timer event that searches for documents to assemble. These documents are created for different "carriers" so there are different modules and procedures/functions where they are assembled and objects created.

When these documents are finished the objects are never destroyed (Set objWord = Nothing....Or Set objBookMark = Nothing). The application then searches for other documents to create and when it finds another carrier it assembles it's documents and the whole thing is done over again with a different set of Word objects.

Hope that helps! Thanks for your help!!!!!
 
<As far as I know the references to the objects are never released because they are never set to nothing.

Then you really need to know more about it. As we've mentioned several times here, when an object goes out of scope, it is automatically released. If you'd like me to explain a bit more about scope, post back. :)

You may want to check and see if any of your procedures (subs or functions) both creates objects and keeps looping around somehow without ever getting to the end until someone manually breaks the loop. A concept like this
Code:
Sub Main()
Dim q() as Object
redim preserve q(0)
Do while true 
   set q(ubound(q)) = New Widget
   Redim preserve q(ubound(q)+1)
   DoEvents
Loop
End Sub

Public Sub Command1_Click()
End
End Sub
would run sub main forever until someone clicked the command button, and none of the objects would ever go out of scope. This is really horrible architecture, by the way. If you have something along these lines, it needs to be rearchitected not by setting objects to nothing, but altering your procedural structure.

Based on your explanation, you may be doing something like this. What do you think?

HTH

Bob
 
There is a real good reason to set your objects to Nothing in time: circular references.

Suppose you have written a resizer class that you pass a form and a list of controls to be resized. You instantiate it from the form, in a class-level variable. You now have two objects pointing at each other: the form and the resizer. If you set all the "outside" references to the form and the resizer to nothing, these objects will not be destroyed, as they still point at each other, and are now beyond reach of the rest of your code.

This is something to be aware of. For instance, if you create collection classes that have members with a reference to their "origin" collection. Or for an application object that is passed through your whole object structure. Or for any object that has a "parent" property.

If I have a program that does not want to terminate (remains visible in the task manager), the problem is usually in circular references.

So back to the original question. It makes no difference if you set the object to Nothing soon or late, unless the program crashes before getting a chance to clean up. In many circumstances it is also safe to rely on Visual Basic's own cleanup. Only if you have a chance of a circular reference, you must control the cleanup yourself.
 
I mentioned out-of-process servers earlier and now you've revealed Word is part of this scenario.

Many such automation servers are designed primarily as user (manual) applications supporting multiple "sessions" - including automation sessions. Often they use one of several techniques to keep themselves running even if no clients hold references to instances of the objects they expose, handling their own lifetime management through internal client counts. Considerable overhead can be involved in terms of state retained by an automation server: loaded documents, contents of private clipboard extenders, accumulated metadata regarding the document or data being operated on, "undo" queues, etc.

So as I said before, use the Quit method before releasing the reference (by scope exit, setting to Nothing, whatever). This is pretty old hat stuff with Office applications. You might look at:

Communicating with Other Applications
The CreateObject function starts a Word session that Automation will not close when the object variable that references the Application object expires. Setting the object reference to the Visual Basic Nothing keyword will not close Word. Instead, use the Quit method to close the Word application.

Other important factors are presented in:

Considerations for server-side Automation of Office
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when run in this environment.

The gist of it is: Do not automate Word as a reporting tool. Generate HTML or RTF reports instead.
 
Thanks much for the replies. I didn't realize this would create so much feed-back which is why I didn't mention Word in the beginning.

The Quit method is eventually used in the code but soooo many things happen prior to that - as I mentioned the bookmark objects - and there's a ton of them.

I will look into seeing if I can easily create the html or rtf files and convert them to the Doc format(which is what is expected by another application). Not sure how much luck I'll have there because of corporate reasons like "we don't have time".... I'm sure you're all familiar with that.

thanks again all
 
<If you set all the "outside" references to the form and the resizer to nothing, these objects will not be destroyed, as they still point at each other, and are now beyond reach of the rest of your code.

Don, I took your first example, and attempted to replicate it as follows:

Create a standard exe project. Add a second form, and a class module. In the class module, do something like this:
Code:
[COLOR=blue]Public Sub ResizeIt(cForm As Form)
With cForm
    Debug.Print .Top; .Height; .Left; .Width
End With
End Sub
[/color]
Now, in Form2, put this code:
Code:
[COLOR=blue]Dim x As myResizer.Resizer

Private Sub Form_Load()
Set x = New myResizer.Resizer
x.ResizeIt Me
End Sub
[/color]
And finally, in Form1, add a command button and put this:
Code:
Private Sub Command1_Click()
Load Form2
Unload Me
End Sub
[/color]

I find when you run this that there are no open forms and the program does indeed continue to run. I do not find, however, that it is because of a circular reference. Rather, it is because I added a form to the forms collection without showing it, and then failed to remove it. Setting x to nothing in Form2's Unload event has no effect; Unloading Form2 before Unloading "me" causes the program to terminate regardless of the scope of the variable x.

So, can you perhaps share some code that demonstrates a circular reference, which can be broken by specifically setting an object variable to nothing? I'm unable to come up with anything.

Thanks,

Bob
 
OK: now the next step (what I meant). The class module should contain something like:

Code:
private WithEvents mrfm

private sub mfrm_Resize
 '...etc. Trap the resize event here to move/scale the controls
end sub

And implement a constructor-like method to initialize mfrm with the caller form. Now there is a circular reference: mfrm points to the form, and x inside that same form points to the resizer.

The way to escape from that is to have one of the two objects call a cleanup routine on the other.

Best regards.
 
Ok, I see what you're up to now. I don't believe it works, though. I tried it, and the class doesn't listen for the events even though the WithEvents keyword has been specified. Specifically, I did this:

In a class called FormWrapper:
Code:
Option Explicit
Public WithEvents cForm As Form

Public Sub LoadForm(fName As String)
On Error Resume Next
Set cForm = Forms.Add(fName)
If Err.Number Then
    Err.Raise vbObjectError + 1, App.Title, "Form not found in collection"
End If
End Sub

Private Sub cForm_Resize()
With cForm
    Debug.Print .Caption, .Top, .Height, .Left, .Width
End With
End Sub

In a standard module:
Code:
Option Explicit
Public fw As FormWrapper

Sub main()
Set fw = New FormWrapper
fw.LoadForm "Form1"
Form1.Show
End Sub

And no code in Form1. Resizing the form does not call the event handler in the FormWrapper class.

My underlying point is that I've never found a situation where manually clearing the reference pointer is necessary, except situations that ought to be avoided in the first place. I don't believe I've ever done this in production code, actually, and find myself not in agreement with those who suggest that it's best practice to always do so.

Feel free to demonstrate something that changes my mind. Perhaps you can correct the code I've given above, or give an example of your collection/parent circular reference.

Bob

p. s. I'd like to amend my previous "would run sub main forever" to "would run sub main until the system ran out of memory."
 
My 2 cents worth ...

I'm with the re-engineered crowd. Sounds to me like you've got "flakey" errors that you might or might not be able to localize ... especially if this thing is organic and called from multiple sources.

Your being told that you don't have time to do it right, just have time to do it over. Been there, done that. You always get blamed and never get to do it right. Make sure that you have something in writing that says you shouldn't do a complete re-write. Otherwise, when the s*** hits the fan you're right in front of it.

Good Luck
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top