Skip to main content
gamedev.net
🔒 Locked

C# finalizer

Started by SiS-Shadowman Sep 8, 2010 at 5:53 AM 8 replies 1.8k views
Original Post
SiS-Shadowman
SiS-Shadowman
Still in the process of learning c# ;)
A lot of sources tell me that I should never rely on the finalizer being called at all, so I'm planning to follow that advice.
However I'm unsure if my current approach is really that useful:
Imagine a simple entity/component system where component has a single responsibility (drawing a mesh, wrapping around a physical body for the simulation, etc...). I called the latter component Collidable and it adds the physical body to the simulation in its constructor. If I were using c++ I would simply remove the body from the simulation in the destructor, but that is no longer an option. One possible solution would be to make the Component implement IDisposable. However the Drawable component should not dispose of it's mesh, since it may be used by other components as well.
*edit* Would it be okay to not call Dispose on an object, when it has a one-to-many relationship to the object about to be disposed?
What are your thoughts on this?

[Edited by - SiS-Shadowman on September 8, 2010 6:11:55 AM]
Echkard
Echkard
The only reason to call IDispose is if your entity is holding a very large amount of memory or some other limited resource. Otherwise, its almost always best to simply let the GC handle cleanup.
Telastyn
Telastyn
Quote:
Original post by Echkard
The only reason to call IDispose is if your entity is holding a very large amount of memory or some other limited resource. Otherwise, its almost always best to simply let the GC handle cleanup.


QFE.

Performance will suffer if you don't play nice with the GC.

Also, you pretty much can rely upon the Finalizer being called. From what I understand the only time it might not be is during catastrophic failure when your program is closing down anyways.

Not that you should for something like this. It's not C# style to do these sort of things on construction/destruction.
rip-off
rip-off
Dispose() is like "begone, foul object". You are expected not to touch it again. It is generally reserved for dealing with external resources.

The finalizer is just as a double-check, so that if you forget to properly dispose of an object that you shouldn't get a resource leak in a long running process. It is a bit of a hack though.

In your case, you want deterministic removal, but removing a Collidable object from the simulation doesn't mean you couldn't add it again. In a managed language, you just explicitly handle this. It is a bit of a pain, but that's the price of a garbage collector.

Ideally you want to do it in such a way that removing the object from the list of collidables also removes the reference in the Collidable object. You can write link() and unlink() helper methods that achieve this. This keeps to code easy to unit test.
geo2004
geo2004
I am by no means a C# guru, but the only times I've ever used Dispose() is on database related objects, like SqlConnection, SqlCommand, SqlDataAdapter, etc. Calling Dispose() on these objects (especially the connection) is pretty important to make sure that they get cleaned up and any connections get closed. I've never actually implemented IDisposable myself.

Also, I'm not 100% sure on this, but I think that if you set an object = null, the GC will clean up that memory on the very next pass.
Rycross
Rycross
Quote:
Original post by Echkard
The only reason to call IDispose is if your entity is holding a very large amount of memory or some other limited resource. Otherwise, its almost always best to simply let the GC handle cleanup.


Dispose has nothing to do with memory. Its for releasing external resources. Connections, sockets, file handles, mutexes, etc. Calling IDispose.Dispose makes no guarantee that memory for that object will be released sooner.

Quote:
Also, I'm not 100% sure on this, but I think that if you set an object = null, the GC will clean up that memory on the very next pass.


There is no such guarantee.
Promit
Promit
Quote:
Original post by Telastyn
Also, you pretty much can rely upon the Finalizer being called. From what I understand the only time it might not be is during catastrophic failure when your program is closing down anyways.
It has nothing to do with failure of any kind. If your program is being closed, it's very possible finalizers will not happen. From this article:
Quote:
When an application terminates, some objects are still reachable and will not have their Finalize method called. This can happen if background threads are using the objects or if objects are created during application shutdown or AppDomain unloading. In addition, by default, Finalize methods are not called for unreachable objects when an application exits so that the application may terminate quickly. Of course, all operating system resources will be reclaimed, but any objects in the managed heap are not able to clean up gracefully. You can change this default behavior by calling the System.GC type's RequestFinalizeOnShutdown method. However, you should use this method with care since calling it means that your type is controlling a policy for the entire application.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Echkard
Echkard
Quote:
Original post by RycrossDispose has nothing to do with memory. Its for releasing external resources. Connections, sockets, file handles, mutexes, etc...
Not quite true. It's actually for disposing of any unmanaged resource. If you allocate a chunk of unmanaged memory in your entity, you need to deallocate it in finalize. If its a large chunk of memory, you're better off doing it immediately through Dispose.
SiS-Shadowman
SiS-Shadowman
Thanks for all those answers.
I always forget that the Dispose method should be used for unmanaged resources, therefore it would be the wrong place for removing the collidable from the physics simulation. I will follow rip-offs advice and implement my own method to do that.
CadetUmfer
CadetUmfer
You don't want to add the body to the simulation in the constructor / remove it in the destructor anyway. Having a "Collidable" that's fully constructed, but not part of a simulation yet is almost certainly a scenario you'll want to support. It's best to explicitly manage adding to/removing from the simulation, rather than try to couple that to the (unrelated) object creation/destruction.

And remember: A correctly-written program cannot assume that finalizers will ever run.
Anthony Umfer

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.