Useless Garbage Collection in C#?

  • Thread starter Thread starter Born
  • Start date Start date
B

Born

Here are my challenges to you:

1) Suppose object A has to do cleanup before it dies. Also suppose there are
multiple references to A. How can I determine when and who to call Dispose
(if you use Dispose for the cleanup).

2) Suppose there are some other sources who reference A through handles.
That is, those sources do not reference A directly but through an
intermediate handle mechanism. The purpose is not to interfere with the
lifetime management of A, but to use A when it exists and to give it up when
it's gone.

Without GC, I can do them pretty easy and good (for example,in C++). But
now, en... Anybody could give me a solution?
 
Born said:
Here are my challenges to you:

1) Suppose object A has to do cleanup before it dies. Also suppose there are
multiple references to A. How can I determine when and who to call Dispose
(if you use Dispose for the cleanup).

2) Suppose there are some other sources who reference A through handles.
That is, those sources do not reference A directly but through an
intermediate handle mechanism. The purpose is not to interfere with the
lifetime management of A, but to use A when it exists and to give it up when
it's gone.

Without GC, I can do them pretty easy and good (for example,in C++). But
now, en... Anybody could give me a solution?

If we talk about allocated memory inside .NET, then you don't
do anything. .NET will handle that for you. You do not do
any cleanup.

If you use resources outside of .NET, then you implement
IDisposable and call Dispose on the object.

Arne
 
Born said:
1) Suppose object A has to do cleanup before it dies.

It is a resource then, and not just memory. GC is for memory, not
resources.
Also suppose there are
multiple references to A. How can I determine when and who to call Dispose
(if you use Dispose for the cleanup).

The same way you would in C++.
2) Suppose there are some other sources who reference A through handles.
That is, those sources do not reference A directly but through an
intermediate handle mechanism. The purpose is not to interfere with the
lifetime management of A, but to use A when it exists and to give it up when
it's gone.

You'd usually use WeakReference (if it's only memory you're interested
in) and possibly subscribe to the death of A (if you're also interested
in resource usage).
Without GC, I can do them pretty easy and good (for example,in C++).

Two things to remember: GC is additive - you can still do manual memory
management if you must (whether object pooling or other mechanisms), and
GC is for memory - i.e. collecting the memory used by objects, not
resources.

-- Barry
 
The same way you would in C++.

In C++, I use reference counting and smart pointers. Because of the stack
object capability, the whole process is quite automatic. I don't exactly
know who triggers the cleanup. But for Dispose in C#, the user must
explicitly trigger it, which is the problem.


You'd usually use WeakReference (if it's only memory you're interested
in) and possibly subscribe to the death of A (if you're also interested
in resource usage).

WeakReference seems an alternative for handles. I'm checking it.

Two things to remember: GC is additive - you can still do manual memory
management if you must

I want to develop a reference counting + smart reference mechanism. Although
it's a waste on GC, it makes the destruction points determined ( good for
CPU/resource heavy but memory cheap objects ) while alleviates the problem
of who should trigger the destruction points. However, in order to do that,
I need stack object capability. I don't know how to do it because my lack of
experiece about C#.
 
2: is WeakReference
1: if the cleanup is unmanaged, then *an* option is a finalizer.
Personally, I prefer to ascribe lifetime ownership to one (only) of the
holders, such that it is absolutely responsible for cleaning up after
itself (via Dispose); I would tend to do this by propegating
IDisposposable to this holder class, and so-on.

Marc
 
I've checked WeakReference. It seems a good alternative to handles although
my MSDN 2005 says an exception will be triggered if the referenced object
has finalized ( I did not experience any exception in my test).
 
In C++, I use reference counting and smart pointers. Because of the stack
object capability, the whole process is quite automatic. I don't exactly
know who triggers the cleanup. But for Dispose in C#, the user must
explicitly trigger it, which is the problem.

The user should not be absolutely required to use it. If the user forgets
to Dispose, put the cleanup in the Finalizer. To prevent the Finalizer
from running in case the user do remember to Dispose, use
GC.SuppressFinalize in the Dispose method.
 
Born said:
I've checked WeakReference. It seems a good alternative to handles
although my MSDN 2005 says an exception will be triggered if the
referenced object has finalized ( I did not experience any exception in my
test).


Sorry it's my misunderstanding of the MSDN documentation. The exception
occurs when the WeakReference itself has finalized.
 
Born said:
In C++, I use reference counting and smart pointers.

Maybe you're not aware of it, but reference counting is GC too ;)
I want to develop a reference counting + smart reference mechanism.

Why? I suggest you take a careful look at things such as SafeHandle, and
read up on the recommendations on how to wrap resources in .NET, and how
to properly implement finalizers etc.
Although
it's a waste on GC, it makes the destruction points determined ( good for
CPU/resource heavy but memory cheap objects ) while alleviates the problem
of who should trigger the destruction points.

Can you describe your CPU/resource heavy types a little more? I think
that you may be at risk of trying to apply a C++ solution to a general
problem.
However, in order to do that,
I need stack object capability. I don't know how to do it because my lack of
experiece about C#.

You could try working with some IDisposable pattern, and ask that users
use 'using' statements to protect the resources.

-- Barry
 
The user should not be absolutely required to use it. If the user forgets
to Dispose, put the cleanup in the Finalizer. To prevent the Finalizer
from running in case the user do remember to Dispose, use
GC.SuppressFinalize in the Dispose method.

If you depend on Finalizer, then there will be a delay between the wanted
destroy and the actual destruction. There are two bad effects for it:

1) CPU/Resource intensive but memory cheap objects
These type of objects can make the delay long enough for the application
to behave badly.

2) Logic disorder to user
Suppose we're doing a 3D game. A radar is monitoring an target.
Obviously, radar should hold a handle or a WeakReference, whatever you like,
to the target. If we do not make a determined destruction, then the radar
watcher (the gamer) will be quite confused. Is the target destroyed or not?
You can not tell him, hey, it's killed but wait for the GC to make it. Sure,
you can deploy other methods and logics on the target in order for the radar
to determine it's detroyed or not, but that's certainly not as natural as
determining it by the condition of whether an object is destructed or not.

As a conclusion, I would say it's a serious defect of C#, if there is no way
to do stack objects.
 
Born said:
I've checked WeakReference. It seems a good alternative to handles although
my MSDN 2005 says an exception will be triggered if the referenced object
has finalized ( I did not experience any exception in my test).

This may help... this is how I think of WeakReference.

For any object, there are two kinds of references you can hold to it:
strong references that require that the object be kept alive in order
that the references be useful, and weak references that will use the
object if it's available but don't particularly mind if it disappears.
Most references are of the first type, strong. Some references,
particularly certain types of event subscriptions, are conceptually of
the second type.

For example, I use weak references to subscribe to static events. I
want the object to be notified when, say, the user changes the screen
resolution, but I don't particularly care if the event occurs and
discovers that the object is gone. Or, from the other angle, it's not
worth keeping the object alive just to receive this kind of event.

The trick, as Marc pointed out, is to design your program so that every
resource has exactly one (strong reference) "owner" at any time, so
that it can be disposed when that owner is finished with it. Ownership
may pass from one owner to another, but in the end you know whose
responsibility it is to dispose of the resource. If you can manage to
make every other reference except the owner a "weak reference" then
you're done.

Sometimes, however, this isn't possible. Sometimes you really do have
multiple owners of a resource. In that case you have to implement some
sort of reference counting scheme like in C++. The only bummer is that
in C# you can't invoke code upon assignment so you can't do auto-magic
reference counting. You can do something close, though. You could use a
secondary, IDisposable object to hold a reference to your resource,
then use "using" to ensure that the reference counting would be correct
no matter what. Something like this:

public class ReferenceToResource : IDisposable
{
private Resource _res;
private bool _disposed = false;

public ReferenceToResource(Resource res)
{
this._res = res;
res.AddReference();
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

public virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
this._res.RemoveReference();
}
this._disposed = true;
}
}

public Resource Resource
{
get { return this._res; }
}

~ReferenceToResource()
{
Dispose(false);
}
}

I make no claims about the suitability of this code... I just invented
it, so it may be buggy! In particular, I was undecided whether to put
the this._res.RemoveReference() within the if (disposing) or not. I'm
pretty sure it belongs there, but I'm open to being corrected.

Once you have this wrapper, you can use it like this:

using (ReferenceToResource ref = new ReferenceToResource(resource))
{
... do stuff with "resource" ...
}

The reference count will be released when leaving the scope of the
"using", whether normally or because of an exception.

You could also add the ReferenceToResource to aggregate structures if
you like, or create structures that manage the reference count
themselves, automatically.

It's not nearly as nice as C++, but fortunately the GC usually makes
this sort of thing unnecessary.
 
Maybe you're not aware of it, but reference counting is GC too ;)

Yes, but how can you develop a robust reference counting with C#, in the
absense of smart pointer support?

Why? I suggest you take a careful look at things such as SafeHandle, and
read up on the recommendations on how to wrap resources in .NET, and how
to properly implement finalizers etc.

See my description on the negative effects caused by Finializers.

Can you describe your CPU/resource heavy types a little more? I think
that you may be at risk of trying to apply a C++ solution to a general
problem.

Resource heavy objects are common: objects holding file handle, network
connection and so on.
CPU heavy objects refer to those who have internal threads running.

Both of these objects can be memory cheap, of course.

You could try working with some IDisposable pattern, and ask that users
use 'using' statements to protect the resources.

Yes, 'using' it's the only way I found robust. However, it's rather ugly in
syntax, if you have experience with Smart Pointers.

Born
 
It's not nearly as nice as C++, but fortunately the GC usually makes
this sort of thing unnecessary.


As I have mentioned, "using" becomes the only way I found robust till now.
However, it's not "nearly as nice as C++", it's far from as nice as C++.
Reasons:

1) Ugly syntax. Please compare smart pointers.
2) Not safe. Some of us may forget to use it.
3) Not correct by itself. Imagine a ReferenceToResource as a variable
member. "Using" does not help. The only way is to ask the user to call
Dispose of every such member in the host class's Dispose.

Moreover, it's not good to say GC usually makes this sort thing unnecessary.
It hurts the usage consistency. Suppose you are providing a library or
framework, it's really bad to tell your customer to use ReferenceToResource
on this and not on that. Moreover, there is more potential risk. Suppose a
ReferenceToResource object as a variable member of a non-ReferenceToResource
class, then the trick immediately becomes invalid.
 
Hi,
Not all programming languages solve problems as good as others do and tricky
solutions -generally- introduce bugs or unhandled situations. If you want to
drive C# on C++ s way I am sure you can do. But if you have two different
type of gun to shoot, I think you should select most proper one for your
game rather than to try to use one's bullet on another.
 
You are completely missing the point of a garbage collector. Implement the
IDisposable interface and model, which tells the runtime that you have to
specifically deallocate resources of some sort. Put your cleanup routines
in the IDisposable routines and don't worry about it. If you must control,
in code, the cleanup timing, implement a Close method that simply calls your
IDisposable interface that handles the actual cleanup an then either use the
C# using block or the following try catch finally technique:

myClass ClassObject = null;
try {
ClassObject.Open
// Processing
} catch (Exception ex) {
// error handler
} finally {
ClassObject.Close()
}

Mike.
 
Born said:
As I have mentioned, "using" becomes the only way I found robust till now.
However, it's not "nearly as nice as C++", it's far from as nice as C++.
Reasons:

1) Ugly syntax. Please compare smart pointers.

Oh, agreed. But we're trying to shoehorn a C++ solution into C# here,
and I dreamed the code up in 5 minutes. I'm not touting it as a great
solution... just showing what's possible.
2) Not safe. Some of us may forget to use it.
3) Not correct by itself. Imagine a ReferenceToResource as a variable
member. "Using" does not help. The only way is to ask the user to call
Dispose of every such member in the host class's Dispose.

Moreover, it's not good to say GC usually makes this sort thing unnecessary.

Don't forget: Dispose is _optional_. The GC will dispose the object
while it's finalizing anyway. The only thing Dispose gets you is that
the resource will be released sooner. The bottom line is that C# does
not have deterministic destruction, and the corresponding deterministic
cleanup of resources the way that C++ does.

Whenever I get into this sort of situation, two things occur to me:

1. C# was created by very smart people, and is used extensively all
over the world. It is extremely unlikely that my problem is so special
and unique that nobody else has encountered it, and nobody else has
found a solution.

2. If I discover that nobody else has found the solution I'm expecting,
then I'm probably suffering from a mental disconnect with the language
and/or platform. I'm designing from the wrong point of view, and so I
arrived at a place where I need a solution that doesn't exist. What I
have to do is back up to the original problem, and see how C# intended
I solve _that_.

To the latter point, you're trying to do deterministic destruction in
C#. C# doesn't do that. Perhaps the problem is that you're trying to
impose a C++ solution on C#. Perhaps you need to back up, give a
broader description of the problem, and see if we can come up with a
solution. The answer is probably that you don't need deterministic
resource cleanup at all, so the "problem" goes away.

Lots of people out there write programs in C# that use resources and
dispose of them. It can be done, and it can be done nicely. It just
appears that it can't be done in the way that C++ does it.
Suppose you are providing a library or
framework, it's really bad to tell your customer to use ReferenceToResource
on this and not on that.

True, but there are loads of libraries out there that allocate
resources and dispose of them. Again, surely there must be a
_different_ solution that doesn't involve smart pointers, or my hackey
little ReferenceToResource class.
Moreover, there is more potential risk. Suppose a
ReferenceToResource object as a variable member of a non-ReferenceToResource
class, then the trick immediately becomes invalid.

No, it doesn't. A .NET standard says that anything that owns or can own
an IDisposable object must itself implement IDisposable. Again, there's
no guarantee that the client will call Dispose on the object, but
calling Dispose in C# is supposed to be "good practice" but not
required: the GC will eventually call it on finalization.
 
Ciaran said:
I don't know advanced c++ but what is the difference between a c++ stack
object and a c# struct?

A C++ object may have a destructor, and the language makes relatively
strong guarantees about calling it.

-- Barry
 
Born said:
Yes, but how can you develop a robust reference counting with C#, in the
absense of smart pointer support?

You don't. You use the GC instead. It's a different language, with
different solutions.
See my description on the negative effects caused by Finializers.

Finalizers are a last line of defence effort at recollecting resources.
I'm not sure what description you're referring to, but I personally
don't rely on them, always calling IDisposable.Dispose() instead.
Resource heavy objects are common: objects holding file handle, network
connection and so on.

The objects you've described (file handles, network connections) are
rare, not common, in my experience. They're a vanishingly small
proportion of objects in the system, and they almost always have
well-defined locations in an architecture - i.e. their lifetimes are
easily reasoned about.
CPU heavy objects refer to those who have internal threads running.

Both of these objects can be memory cheap, of course.

You have still only described your problem in general terms. If you
describe your problem specifically, then I think you'll get better help.
Yes, 'using' it's the only way I found robust. However, it's rather ugly in
syntax, if you have experience with Smart Pointers.

Sure. You might want to consider C++/CLI instead of C#, which implements
IDisposable in what looks like a C++ smart pointer way.

-- Barry
 
Another big difference is that in C++ you create a type (class) and
then later, while you're using it, decide whether you want the instance
to live on the stack or the heap, or whether you want it to live
in-line inside another object's state, or have that other object hold a
reference to it.

In C#, you make that decision once, up front. If you create a class,
then you're always holding a reference to it. You can never push the
actual instance on the stack, and you can never store it in-line within
another object (unless that other object is a descendant). If you
create a struct, then all local variables of that type always live on
the stack, never on the heap, and it always lives in-line within any
enclosing types, never as a reference.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top