views:

218

answers:

6

I'm ready about Memory management in C# from the book "Professional C#"

The presence of the garbage collector means that you will usually not worry about objects that you no longer need; you will simply allow all references to those objects to go out of scope and allow the garbage collector to free memory as required. However, the garbage collector does not know how to free unmanaged resources (such as file handles, network connections, and database connections). When managed classes encapsulate direct or indirect references to unmanaged resources, you need to make special provision to ensure that the unmanaged resources are released when an instance of the class is garbage collected.

When defining a class, you can use two mechanisms to automate the freeing of unmanaged resources.

  1. Declaring a destructor (or finalizer) as a member of your class.
  2. Implementing the System.IDisposable interface in your class.

I didn't understand few things:

  1. "unmanaged resources (such as file handles, network connections, and database connections)". Whats the big deal about them? How come they are unmanaged? (or) Why can't GC managed these resources?

  2. What code would we place in finalizer or Dispose() method of the a class and what exactly that code would look like? Some examples using these resources, would be of lot of help.

+2  A: 

1.) The GC does not know how to close external resources properly. Of course he could kill a network connection (which is, in fact, what he does if you don't disconnect i.e. a database connection). But the database isn't being notified of closing the connection.

Similar goes for file streams. Is there still something in a buffer? Does that have to be written to file before closing the file handle? The GC does not know about this - the accessing code does.

2.) Is what follows from that. So if you have open file streams and an internal buffer - in the dispose method you would flush the buffer, write it to the file and close the file hanlde.

For usual, you don't directly access databases. You use libraries managing this for you.

In most cases it's enough, to dispose those external resource managers (Db connection, filestream, network classes) if your class is being disposed.

Sebastian P.R. Gingter
A: 

For 2) see here: http://msdn.microsoft.com/en-us/library/fs2xkftw.aspx

Konamiman
+8  A: 

Some classes on the .NET framework are just wrappers of Windows APIs or third party assemblies. These APIs are not managed code (they can be written in C++ or they are old COM assemblies) and the garbage collector does not know when they are no longer required by the application.

For example, when you open a file of disk, it will remain open until you tell it to close the file. If you destroy the pointer to the file (i.e. leaving the scope) without closing the file, this file will remain open and locked.

The Dispose method implemented on the Framework for these classes calls the inner Close method required to finalize the instance in a clean way. So all the classes that wrap unmanaged code should implement the Disposable interface to assure that a closing method it's implemented.

Then when you instance that class it is a good practice to do it with the using statement because then when you leave the scope the Dispose method is called automatically.

despart
This makes sense. I always looked GC from memory leaking point of view. So, its just about the memory.You do not also want to leave the files or connections to the database open. These should be manually closed. right?If the file is not closed and object gone out of scope and even the application is also exited. Still will not be able to delete or move this file since, as prompted by OS "Cannot move/delete/modify/rename file as its in use". But the fact is that process is no longer running. I experienced this few times. I had to restart/re-login to fix this.
claws
You can use application like Unlocker (http://ccollomb.free.fr/unlocker/) to fix problem with locked files.
Majkel
+1  A: 

Unmanaged resources are handles to resources owned and controlled by the operating system (other than memory of course).

The GC doesn't clean up memory immediately at the point that there are no longer any references to an object - it may leave it for a long time. If it did this with files, network and graphics handles it would potentially take up a lot of operating resources and only release them occassionaly.

In order to release these unmanaged resources back to the operating system you need to explicitly release them by disposing them. Hence the use of IDisposable and the using keyword.

Matt Breckon
+2  A: 

This is a good question and one that a lot of developers don't seem to understand.

At a high level, managed resources are resources that are allocated and tracked by .Net. The memory used by the resource comes from a pool allocated to .Net and the .Net runtime tracks all references between managed resources. This tracking (I'm sure this is the wrong term, but will suffice here) allows the .Net runtime to know when a given resource is no longer being used and thus eligible to be released. Unmanaged resources therefore, are resources allocated outside of that .Net managed pool and not tracked by the runtime. Most often, these are references to OS or external application resources. There are all sorts of complicated reasons why the .Net runtime cannot "see" into an unmanaged resource, but I like to think of it like this: .Net is a walled development garden that you must enter to use. You can poke a hole in that wall to see outside (ie, PInvoke) but you cannot own a resource on the other side.

Now, on to the second part of your question. Bill Wagner has a great discussion on how to implement Dispose methods and why in his book Effective C#. There are also some really good answers about this here and here.

Hope this helps.

akmad
+3  A: 

The real question here is about urgency. As the garbage collector explicitly tracks memory, it will know when there is a need to free up memory by cleaning unreferenced objects. This can happen several times a minute, or once an hour, or even never (if no new objects needs to be created). But the important thing is that it does happen when needed.

But memory isn't the only resource that is limited. Take files. Usually only one application at a time can open a file as it can become messy if several people tries to write to the same file. Databases have a limited amount of connections. And so on. The garbage collector doesn't track any of these resources. And it has no idea of how urgent it is to close them.

Sure, you could open a FileStream and read from it without closing it afterwards. if you null out the reference to the object, eventually the garbage collector will probably decide to collect the FileStream object, which will have its Finalizer run and the file will get properly closed. But that could take a long time, and in the meanwhile the file is locked.

With database connections it is far more urgent, as there is a very limited amount of collections available, so if you open too many connections without disposing of them you will eventually get an error as you will have a bunch of database objects having open connections that lie waiting in the garbage collector queue.

Properly disposing of Disposable object is therefore good practice. Sometimes you could get away not doing so, but it is poor style. If an object implements IDisposable, it is because it wants you to clean it up when you are done using it.

Marcus Andrén