to dispose or not ?

  • Thread starter Thread starter Michel Posseth [MCP]
  • Start date Start date
Hmmm. Ok, then what we've learned here is two things:

1. What I've described (setting to Nothing *can* actually prevent the
object from being collected) is true for Debug mode.
2. Setting an object to Nothing in release mode does nothing (because the
JIT compiler will ignore such statements).

Correct?

If so, the moral of the story, which I think we all agree on, is that
setting an object to Nothing doesn't buy you anything.

-Scott
 
Hmmm. Ok, then what we've learned here is two things:

1. What I've described (setting to Nothing *can* actually prevent the
object from being collected) is true for Debug mode.
2. Setting an object to Nothing in release mode does nothing (because the
JIT compiler will ignore such statements).

Correct?

If so, the moral of the story, which I think we all agree on, is that
setting an object to Nothing doesn't buy you anything.

How 'bout a slight modification:

Setting a locally scoped object almost never buys you anything.

It still has merrit with class or module level values, and who knows if you
will never come across some oddsituation where it actually makes a difference on a
local scope? :)
 
As for the code being "too complicated" for the GC to figure out, that
simply cannot happen given that at any time during the execution of a
program, you can always identify memory that is accessible given that you
always have the system memory roots available. If an object isn't
accessible from a root, your code can no longer see it. Note that this is
only true for 100% managed code. As soon as you start calling COM objects

It appears that relatively simple completely managed code is too confusing for the GC to figure out
and requires a GC.KeepAlive to tell it what to do:
http://support.microsoft.com/kb/821779

Michael D. Ober said:
The dotNet garbage collector is, at it's heart, a move to another heap style
collector for the Gen0 and Gen1 heaps and a mark/sweep/compact collector for
the Gen2 heap. What this means is that the runtime keeps a list of all
known starting points for the heaps and either moves the objects to the next
heap or compacts free space out of the heap (Gen2 only). Known starting
points include, but are not limited to, global variables and the stack
frames for each thread. There are NO reference counters in the garbage
collector's managed memory. Setting an object to Nothing simply releases
the reference from the variable to the object in the heap. The problem is
that neither the VB nor the C# (obj = null;) compilers is smart enough to
realize that this statement should simply be ignored and not generate code.

Since I didn't see the entire thread, I'm making an assumption that you are
coming from a VB6 background and that you are using the VS debugger and
seeing that the objects are still accessible after you are done with them.
In debug mode, the compiler internally sets a GC.KeepAlive at the end of
each method (function, sub, property) on all objects created in the current
method that are not returned by the function or property get or attached to
another object. I'm not sure the exact mechanism for this, but the end
result is that objects in debug releases are kept to the end of the method
even if they are no longer referenced, allowing you to inspect their
contents anywhere in the method. In release code, this doesn't happen and
the GC may safely collect these objects in the middle of a method.

As for the code being "too complicated" for the GC to figure out, that
simply cannot happen given that at any time during the execution of a
program, you can always identify memory that is accessible given that you
always have the system memory roots available. If an object isn't
accessible from a root, your code can no longer see it. Note that this is
only true for 100% managed code. As soon as you start calling COM objects
and DLLs outside the managed environment, you need to use the interop
libraries and sometimes the GC.KeepAlive methods to give the garbage
collector the information it needs to avoid collecting memory used to pass
data between the COM and DLL objects and the managed code. The interop and
GC.KeepAlive calls provide a method for the programmer to tell the GC that
specific objects are a known "root" for garbage collection purposes.

Mike Ober.
 
The is the console output if Ctrl-Break is pressed while the console read is active:
Waiting 30 seconds for console ctrl events...
A CTRL_BREAK_EVENT was raised by the user.
Finished!
A CTRL_BREAK_EVENT was raised by the user.

H:\

Note that the event handler is still hooked in and processes the Ctrl-Break -- then it is passed to
the Read method which ends.

However, if garbage collection is forced by adding:
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
between the GC.KeepAlive and the Console.Read. The handler does not get control and the message
after Finished! does not appear.

Finally, if you put a Thread.Sleep(3000) between the last GC.Collect and the Console.Read and press
Ctrl-Break during it you get an unhandled exception because the handler object doesn't exist which
is the expected behavior.

I find the above behavior very confusing. If the console control handler is called when Ctrl-Break
is entered while the Console.Read is active I would expect this to throw an error when garbage
collection is forced as it does if a Ctrl-Break is entered during Thread.Sleep but it doesn't.
 
It seems that my original assertion that setting an object reference to
I got the KeepAliveDemo working. Using Test = Nothing in place of GC.KeepAlive(Test) does not stop
the erroneous execution of the Finalize method. This implies that GC.KeepAlive serves as more than
a marker for a reference.

It is also interesting that this piece of simple code is too complicated for the GC to figure out
when it is safe to release an object. I will start using GC.KeepAlive(obj) everywhere I would
normally have used obj = Nothing.
 
It is also interesting that this piece of simple code is too complicated for the GC to figure out
when it is safe to release an object.  I will start using GC.KeepAlive(obj) everywhere I would
normally have used obj = Nothing.

That code doesn't really represent a mainstream scenario though. I
think you'll find the usefulness of GC.KeepAlive to be quite limited
outside of Win32 or other unmanaged API call scenarios.
 
order. As a general rule, if you aren't using a finalizer or COM interop,
you don't need the GC.KeepAlive() method.

But you don't know what a class you call might contain. Do you have to review the source code of
every class in every managed code assemble that you call? One needs a general rule that will not
lead to intermittent bugs that are difficult to track down.

If I use GC.KeepAlive(obj) where I would have used obj = nothing what is the cost vs the risk of not
using it?

Michael D. Ober said:
Stewart Berman said:
I got the KeepAliveDemo working. Using Test = Nothing in place of
GC.KeepAlive(Test) does not stop
the erroneous execution of the Finalize method. This implies that
GC.KeepAlive serves as more than
a marker for a reference.

It is also interesting that this piece of simple code is too complicated
for the GC to figure out
when it is safe to release an object. I will start using
GC.KeepAlive(obj) everywhere I would
normally have used obj = Nothing.

Be careful that you aren't causing excessive Generational increments. The
example given is in a finalizer, not in primary code. Finalizers and
"unscoped" dispose routines are documented to not occur in any specific
order. As a general rule, if you aren't using a finalizer or COM interop,
you don't need the GC.KeepAlive() method.

Mike.
 
Back
Top