Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

set obj=nothing really necessary?

96 views
Skip to first unread message

Bernd Liebermann

unread,
Jan 29, 2001, 8:32:17 AM1/29/01
to
I'm wondering for a long time if the "set obj=nothing statements" at
the end of a function/procedure are really necessary or just an
indicator for a good coding style. My (german) help tells me that
the object memory is freed if the last variable referencing the
object has gone out of scope. So if my object variable is declared
locally and is the only reference to the object created with the
new-operator, so why setting it to nothing? Somebody got the final
answer for me?

Regards,
Bernd Liebermann

emu...@my-deja.com

unread,
Jan 29, 2001, 9:43:24 AM1/29/01
to
Hi Bernd,

This topic came up for discussion a few weeks ago under the title "set
objects to Nothing on error / at end of function?". Do a search for
that title or if you have a Deja account, you can use this link to see
the whole thread:

http://x65.deja.com/viewthread.xp?
thitnum=4&mhitnum=0&AN=711058980.1&CONTEXT=978471119.735445024&frpage=th
readmsg_ct.xp&recnum=%3cuFo8eGPdAHA.2060@tkmsftngp05%3e%
231/1&back=microsoft.public.dotnet.languages.vb

Alternatively, I saved the highlights of the discussion to a text file
as a reference for myself which I've copied and pasted to this
message. Different posts are seperated by a series of equal signs (ex:
========).


==============================================

Is there a definitive answer as to whether or not you should set all
objects to Nothing explicitly at the end of their scope, i.e. either
when exiting a function, terminating a class instance or shutting down
a program? I have heard it both ways directly from MS Tech Support and
in articles in magazines like VBPJ.

Specifically what I mean is, suppose I have a function (or class etc.)
which creates some local objects:

Dim objFoo As TypeLib.ClassName1 ' or As Object
Dim objBar As TypeLib.ClassName2 ' or As Object

Set objFoo = New TypeLib.ClassName1 ' or CreateObject
("... Set objBar = New TypeLib.ClassName2

... some code that uses these objects ...

At the end of the function, and/or in an error handler, should I kill
them off?

Set objFoo = Nothing
Set objBar = Nothing

Exit Function

Or should I just leave them alone, and trust VB to get rid of them for
me?

Some authors religiously use Set X = Nothing to explicitly deallocate
all objects when they are done with them, while others say "the runtime
engine garbage collection handles this for you automatically, don't
worry about it". I even heard from MS Tech Support that you should NOT
explicitly deallocate objects, that sometimes it does not work properly
and can leave orphaned objects in memory, making a process not
terminate. But, maybe this was a bug in some old versions of VB and is
no longer the case. No one really seems to know.

Now, I realize of course that objects take up resources, so if I am
done with one I could release it right away to get the memory back.
But let's assume these are short, fast functions and the objects
created have low overhead. What I'm wondering about here is the
general practice: deallocate explicitly or not? It is necessary and/or
worth your time to nuke the objects by hand, and thus maintain that
code each time you change the function to use a new object, or should
we just not worry about it?

What I've seen of .NET seems to indicate that all MS languages are
getting garbage collection as part of the common runtime. This makes
me guess that we should not bother with explicitly calling Set X =
Nothing, and just let the runtime handle things.

Any opinions? Any documented problems with doing it one way or the
other?

Thanks everyone

Terry McKiernan
CoStar Group

==============================================

The definitive answer, which I'm sure some will disagree with, is NO.
VB will automatically set all object variables to Nothing when they go
out of scope. For local variables, this happens when the procedure
ends. For module-level variables in class modules (including forms,
controls, etc), when the final release happens on the class (and after
Class_Terminate is run). For modules, when the program terminates.
Setting them to Nothing yourself is a waste of code: VB has to check if
they are Nothing anyway and always generates the code to release them,
so you're just duplicating existing code.

I've also noticed that many people who are religious about the Set =
Nothing do not take the same approach to strings and array types. They
seem to be perfectly happy with letting VB clean these types, but still
religiously maintain that it can't handle object types. You'll also see
code that contains a jump out of a With block (ie, without executing
End With), but still sets all locals to Nothing. The inconsistency here
is that a With block actually generates a hidden local object variable,
but you don't have access to it to explicitly set it to Nothing. VB
treats hidden and visible locals exactly the same when a procedure
terminates. Since you are forced to implicitly trust it with the hidden
variables, you should also trust it with the ones you define.

Let me preempt one comment from the opposing camp. A common argument
for the explicit 'Set = Nothing' approach is that this documents the
intent of the code, and even makes it easier to port the code to other
languages. I don't buy into this. Since the explicit code does not
change the behavior of your app in any significant way, it is
essentially untestable, so any port relying on it is relying on
untested code. Also, unneeded teardown code obscures necessary teardown
code buy burying it in a bunch of noise, which makes it harder to
maintain the real teardown code.

There are times when you need to do an explict 'Set = Nothing', but
none of these have anything to do with protecting variables as they go
out of scope. The reasons I can think of are:
1) Breaking circular references. This is generally done in response to
an event or explicit method call. For example, if a form is circular
with a class instance, then Form_Unload is a good place to break the
cycle.
2) A requirement for explicit teardown order. This is rare, but it does
happen. For example, if you apply two UnknownHook objects from my book
to the same object, then you need to remove the hooks (ie, set the
objects to nothing) in reverse order. If you follow the rule to not use
explicit teardown for non-order dependent code, then when you do see
a 'Set = Nothing', you know that the execution order is important.
3) Poorly designed object models. A robust object model allows its
objects to be released in any order and at any time, but you will
occasionally meet one that isn't robust. You should never extrapolate
teardown rules for an explicit object model into general rules for all
VB code. A requirement for explicit teardown should always be
considered an exception, not a rule.

> What I've seen of .NET seems to indicate that all MS languages are
getting
> garbage collection as part of the common runtime. This makes me guess
that
> we should not bother with explicitly calling Set X = Nothing, and
just let
> the runtime handle things.

The VB6 runtime handles this now, but it doesn't use garbage
collection. In fact, the VB6 approach is diametrically opposed to the
GC philosophy. VB6 has a strictly enforced no littering law, while GC
actually forces you to litter. In fact, in a GC system, the 'Set =
Nothing' is even more useless because any Finalize code does not run
immediately as it does with the final release in a COM-based system.
While object systems with teardown order dependencies were frowned upon
in COM, they are considered downright evil in GC land.

- Matthew Curland

===================================

> Whether explicitly using the "set objFoo = nothing" statement carries
a
> performance overhead is an interesting question though - any answers?

Of course there are performance implications. You're running the same
code twice, and the Set = Nothing code is more expensive than what VB
does at the end. Use debug symbols to look at the generated code and
you'll see the cost (Set = Nothing generates a vbaCastObj call, while
implicit teardown generates a series of optimized vbaFreeObj calls).
Also, remember that code size has performance implications as well. The
bigger the program, the longer it takes to load and run.

I would also have to disagree with you that Set = Nothing adds clarity.
I try to only write code that makes the program deviate from the
implicit behavior. By adding extra code that is trying to mimic the
implicit behavior, you make it harder to figure out which lines of code
actually make the program run differently. You would never subclass a
window without actually interacting with specific messages because a
window procedure with nothing more than a CallWindowProc forwarding
call adds runtime overhead and maintainability costs, but doesn't
change the behavior of the program. Why would you ever routinely follow
a coding standard that bloats your program but has no impact on the
behavior of the program? Code that does nothing can never be considered
consistent because it is unverifiable.

- Matthew Curland

===================================

Hi Matt,

I'm one of those programmers who explicitly sets all objects to
Nothing. I think I might be willing to switch religions, but there are
a couple things I don't understand. I've always heard that there were
certain situations were VB would fail to clean up properly. Now, I
always explicitly set my objects to Nothing so I haven't had this
problem but I have heard of other people who have. In fact, just a few
weeks ago, one of the other programmers I work with was having trouble
with his program. (In a nutshell, his program consists of one main EXE
and one ActiveX EXE.) Users were reporting that in certain unknown
situations, the ActiveX EXE remained in memory after it should have
been closed. He couldn't quite figure out why it happened sometimes and
sometimes it didn't. I told him that he should explicitly set all his
objects (forms, classes, database connections, etc.) to Nothing. Since
he has done that, the users haven't had this problem reoccur. Can you
reconcile this with your advice to not set objects to Nothing? Also,
you listed 3 situations where setting objects to Nothing are required.
Are there any other situations, such as buggy third-party components
that might require you explicitly set them to Nothing? Is it possible
that VB itself contains one or more bugs that prevent it from cleaning
up objects properly in certain situations?

Your help is greatly appreciated.

- Jim

===================================

Let's get back to the original question, which is whether objects
should be set to Nothing at the end of a function (or, I'll add, in a
Terminate event). Following this practice is like sanitizing your
garbage before you put in out at the curb. VB will pick up your litter
whether or not it has been scrubbed. I'll specifically address two of
the objects you mentioned (forms, db connections).

If you use the predeclared form variables, or a module level variable
that holds a form object, then those variables are not scoped within a
public class, but they are still considered to be public objects. The
AxExe server will shut down when all public objects have been released,
so a global form variable can theoretically keep the server alive.
There are several approaches to handle this:
1) Don't use the predeclared variables, and don't hold any other module
level reference to a form. If you do 'With New Form1: .Show: End With',
then the visible portion of the form holds the only reference that
keeps the form alive. When you unload the form, the object will be
released automatically.
2) If you do use the predeclared variables, always set them to nothing
when the form is unloaded. If you are using the implicit variable
exclusively for a given form, you can do this in Form_Unload. Of
course, you'll have to adjust this if you move to creating multiple
instances of this form.
3) If you pass a reference to the form to another object, make sure you
clear it out in Form_Unload to clean up an circular references. This
can often be done by setting module variables to Nothing in this event.

For DB objects (recordsets, connections), you should always be calling
Close on these objects before the object variables are set to Nothing.
It doesn't hurt to set the variable to Nothing after you've called
Close (it is usually easier to create a new object than to try to
resurrect a zombied object), but this shouldn't make a difference to
any system resource issues you might be having. If you're calling Close
in Class_Terminate, then the Set = Nothing is just sanitizing garbage.

If you want to find the Set = Nothing statement that actually made a
difference in your friends app then look for the following:
1) The statements that cleared global variables.
2) Statements in events other than Terminate that cleared member
variables of the class
Ignore:
1) Statements in Class_Terminate that clear member variables
2) Statements in any function that clear local variables

Figuring out what was causing the problem might be a good exercise, and
will help to avoid the problem in the future.

VB does not have any bugs that prevent it from clearing objects. Trust
me, you'd see this issue in every project if it did.

- Matthew Curland

=======================================

The semantics of the language set all variables to nothing when they go
out of scope. VB keeps this promise. There are absolutely no cases
where it doesn't release variables when they go out of scope. My point
is that you aren't actually doing anything that VB isn't already doing
for you, and you're kidding yourself if you think you can release all
locals variables by setting the ones you know about to nothing (there
are a ton you never see). Note that this doesn't apply to setting
variables to Nothing when they are not about to go out of scope anyway.
This is of course a perfectly valid practice.

(With exceptions for the cases I stated earlier)
-If you set a local variable to Nothing at the end of the procedure, it
is a wasted effort. You might have to call Close/Dispose methods before
the variable goes out of scope, but that is not the same as setting it
to Nothing.
-If you set a class-level variable to Nothing in Class_Terminate, it is
a wasted effort. If you had a circular reference problem you could fix
by clearing the class's variables, then you wouldn't have gotten to
Terminate in the first place.
-Setting a class variable to nothing in an event other than Terminate
(like Form_Unload) can have an effect on circular references, it is not
always a wasted effort.
-Setting global variables to nothing is not always a wasted effort,
especially if the global variables reference instances of public
objects.

- Matthew Curland

=======================================


In article <118201c089f7$e6149590$46862ecf@cpmsftngxa06>,


Sent via Deja.com
http://www.deja.com/

Bernd Liebermann

unread,
Jan 30, 2001, 9:08:36 AM1/30/01
to
Thank you very much. This summary was really helpful.

Regards,
Bernd

-----Original Message-----
Hi Bernd,


==============================================

Exit Function

Thanks everyone

Terry McKiernan
CoStar Group

==============================================

- Matthew Curland

===================================

- Matthew Curland

===================================

Hi Matt,

- Jim

===================================

- Matthew Curland

=======================================

- Matthew Curland

=======================================

.

0 new messages