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 SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Check Before setting object = Nothing 1

Status
Not open for further replies.

codemama

Programmer
Nov 13, 2007
4
0
0
US
I know there was some debate on whether you should set it to nothing or let VB take care of it.. However it is part of our company coding standards to set the object to nothing when done.

1. Do I need to check if the object exists before setting to Nothing? (more obvious in class vars).
If NOT obj Is Nothing Then Set obj = Nothing

2. Usually we dont create a new object just set it as that type or It is passed in by ref. (Private m_oTempCalls As MSXML2.DOMDocument30)
Do I still need to set to Nothing or check if not Nothing already.

Should I just make sure that any class level object gets set to nothing in the Class_terminate methods?


This is a COM++ app with VB 6 and VS C++

Thanks in advance.
New to the COM stuff..
 
<However it is part of our company coding standards to set the object to nothing when done.
It seems to me a little strange that a group would consider itself more rigorous in applying standards for releasing objects than Microsoft was when they wrote VB6. I argue against this.

< Do I need to check if the object exists before setting to Nothing?
If you have a context where you really can't tell if the object is released or not without checking, then yes. I can't think of one offhand, although I'm sure there are situations like this. I see this construct fairly often, but as a means of dealing with existing code that's too disorganized for the present coder to want to go to the trouble of figuring out whethere the object is instantiated in the given context or not.
 
In many cases you can avoid the issue by using code like;

With CreateObject("SomeApp.object")

'the code

End with

in such cases you are left with nothing to set to Nothing!
 
Our coding standards dictate that every instantiated object should be manually destroyed.
The main reason behind this is that it is all too easy to instantiate an object that uses an internal timer to run pseudo multi-threaded. Non-destruction of a single pointer can leave the object in memory, et viola, memory leak.

A good reason for check whether a pointer is initialised or not is so that you can perform additional tear down code. i.e.

Dim loConnection as ADODB.Connection
loConnection.Connect

Set loConnection = nothing

Assumes that the connection object's destructor will terminate any current connection.

However,

if not (loConnection.State is Nothing) then
if loConnnection.state = adStateConnected then loConnection.disconnect
set loConnection = nothing
end if

If additional tear down code is not required then a good old set loConnection = nothing would be fine.

As for your final question, my answer would be yes; it's just good practice (imo) to explicitly destroy any resource you consume when you're done with it.

(The little bit's of code were just thrown together in the forum editor, their syntax maybe a little wonky ;))
 
They aren't pointers they're references which is something a bit different. It's a little bit like saying a String is a "pointer." It's wrong.
Our coding standards dictate that every instantiated object should be manually destroyed.
The main reason behind this is that it is all too easy to instantiate an object that uses an internal timer to run pseudo multi-threaded. Non-destruction of a single pointer can leave the object in memory, et viola, memory leak.
Goofy things like this are not cured by just setting an object's references to Nothing. You might take a look at Visual Basic Component Shutdown Rules and ActiveX Component Shutdown.

Normally such a class exposes a shutdown method you need to invoke before either explicitly or implicitly dropping the reference.

Not knowing whether a reference variable holds a reference or not at any given point in a program sounds a lot like voodoo coding. Seeting things to Nothing at random is no substitute for being aware of the execution paths your code can take.


But no, setting a reference variable that is already Nothing to Nothing doesn't do anything strange. It's a lot like setting a Long that is already zero to zero. It just clutters the source code and wastes cycles.

There certainly are good places to explicitly drop a reference. This includes object-pooled situations or situations where the reference variable won't go out of scope soon and holds any fairly "heavy" object. But global object references should be avoided anyway, if you use them you have to properly manage them.

A rule like "Set references to Nothing early, often, and always" is just dumb. Just for starters many objects can be handily reused more cheaply than recreating them. Some class factories should only be instantiated once and reused throughout the life of the program.

Lots of factors to consider, every case in unique.
 
Thanks for the info and view points..
I spent most of yesterday wading thru the code and determining what class vars needed to be destroyed in the class_terminate method.

Was able to do a ton of clean up.. And yes, they were setting and object to nothing and then creating it again..

Code is much cleaner now. I let the method vars clean themselves up since none were that large. However, there is supposedly a memory leak somewhere that I need to track down.
 
<in such cases you are left with nothing to set to Nothing!

Gee, I wonder how Microsoft could accomplish automatically releasing an object when encountering an End With statement, and somehow fail to accomplish the same task when encountering an End Sub or End Function statement. Thanks for helping me make the point, Hugh! :)

<all too easy
Nimrod, I'm not sure it's that easy, at least I can't see how to do it. Can you demonstrate how to produce a memory leak when not manually releasing an object?

codemama, if you ever find that memory leak, please publish it. In my experience, memory leaks typically occur in VB when instantiating an object whose code was written in C++.

Or of course, when using anything put out by AOL.

Bob
 
Bob,

Yes, I've noticed Mr Strongm using stuff like the example I gave and suspect there is'nt much wrong with it.

I often see code examples (especially office automation stuff) which begins with a bunch of nested Dims and Sets and ends with a bunch of nested Sets to Nothing. When all of it can usually be done within a With block; without need to Dim objects (into variables/ objects which are defined in your code) at all. Behind the scenes I guess VB is creating the necessary temporary variables/ objects and cleaning up as required when the End With is reached.
 
@ Bob, if I'm not too busy tomorrow I'll throw an example together. I've caught myself out enough times that it shouldn't take too long to replicate :s

I have to say that I have one issue with the use of:

With CreateObject("SomeApp.object")
'the code
End with

In doing so you're creating a late bound reference to the required object. My understanding was that a late bound COM call causes additional marshalling and interface checking and is therefore much slower. But I'm probably wrong.
 
>...much slower. But I'm probably wrong

Technically I believe you are right but the difference is not often worth loosing sleep over. If you are creating a zillion objects then well ...
And in Office applications late binding gives you Office version independence.
 
Nothing really prevents you from using (trivial case):
Code:
With New Scripting.FileSystemObject
    If .FileExists("C:\temp\junk.txt") Then
        MsgBox "Found it"
    Else
        MsgBox "Nope!"
    End If
End With
 
Having reread my post and Bob's interpretation I am not so sure that what I was trying to say has come across correctly. Regardless I have created a demo of what I was trying to get at.

Create a new ActiveX EXE project called "MemLeakDemo".
Rename Class1 to "SomeIface" and ensure it is MultiUse.
Add a form to the project called "frmHolder"
Put a timer on the form called "tmrTimer"
Stick the following code in SomeIface:
Code:
Option Explicit

Dim loHolder As frmHolder

Private Sub Class_Initialize()

Set loHolder = New frmHolder
Load loHolder
With loHolder.tmrTimer
    .Interval = 1000
    .Enabled = True
End With
End Sub


Public Sub SomeTearDownCode()

If Not (loHolder Is Nothing) Then
    loHolder.tmrTimer.Enabled = False
    Unload loHolder
    Set loHolder = Nothing
End If

End Sub

Compile MemLeakDemo.


Start a new Standard Exe project.
Add a reference to MemLeakDemo.
Stick two buttons, cmdLeak and cmdNoLeak, on Form1.
Put the following code in Form1:
Code:
Option Explicit

Private noMemLeak As MemLeakDemo.SomeIface

Private Sub cmdLeak_Click()
'Leave this line in to leak
Set noMemLeak = Nothing

End
End Sub

Private Sub cmdNoLeak_Click()
'Unrem this to stop leaking
If Not (noMemLeak Is Nothing) Then
    noMemLeak.SomeTearDownCode
    Set noMemLeak = Nothing
End If

End
End Sub

Private Sub Form_Load()
Set noMemLeak = New MemLeakDemo.SomeIface
End Sub

Open Task Manager.
Run "Project1" (from within the IDE is fine).
You'll see the MemLeakDemo process is loaded.
If you now click on cmdLeak, Project1 will End but the MemLeakDemo process remains loaded.
---Using Task Manager kill it
---Restart Project1
If you click on cmdNoLeak, Project1 will End and the MemLeakDemo process is terminated.


From a debugging POV it is obvious that the problem is caused the lack of destructor in the SomeIface class; the loaded form is enough to stop the garbage collect from cleaning up the process. This can be remedied by ensuring that the class cleans itself up properly:
Code:
Private Sub Class_Terminate()
Me.SomeTearDownCode
End Sub

Which is fine in this case as we have access to the source.
I have however had the mispleasure of encountering this problem on more than one occasion when using 3rd Party, closed source, components. Because of this we now develop using a rule of "if you create it, you destroy it".

Hope that helps clear up what I was getting at.
 
edit:
Please ignore the two comment lines:

"'Leave this line in to leak"

and

"'Unrem this to stop leaking"

I was originally going to post sample code that did the whole thing in the Form_Load but then decided that use of buttons was easier.
...perhaps we need a "make sure comments are up to date" coding standard too ;)
 
But those are pathological cases, other good examples being automation of Office applications that expect you to call their Quit() methods before dropping your reference.

As Microsoft suggests in those links above regarding object lifetime, these sorts of things are to be avoided! If you're going to do them, fine, but be very clear to describe the need for the shutdown call to anyone using your component library.


The point of this thread was about setting references to Nothing blindly though. In a case such as you describe you can end up with a lot worse than a memory leak, you can leak orphaned processes! Singleuse Active EXEs are the clearest example.

I suppose you're just reinforcing the point that dropping references by rote can get you into trouble.
 
>Because of this we now develop using a rule of "if you create it, you destroy it".

However, as I said earlier, setting the object to Nothing does not destroy it and, even if it did, does not resolve the problem you illustrate here.
 
<But I'm probably wrong.
You're not. :)

<setting the object to Nothing does not destroy it
This sounds interesting. Can you elaborate a bit?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top