Have you ever wondered how applications know how much memory to use, how is that memory distributed or who cleans up memory? All those operations are executed by the Garbage Collector.
What triggers Garbage collector?
- Your system is low on physical memory. Meaning your system has used up almost all of your RAM memory and will start to use page file.
- The memory that is used by allocated objects on the managed heap surpasses an acceptable threshold. This threshold is continuously adjusted as the process runs.
- Application is written to call the GC.Collect method.
.Net framework needs your help with memory, database and network connections. If we do not dispose of connections we are going to run into several problems:
- If for example we are using a file in our application, another instance or user or similar scenario, will not be able to access our file use it or write to it.
- When connecting to a database or network location, we should always dispose of our connection as soon as we finish using that connection, because number of connections to a remote server is not infinite, meaning, we are reducing number of possible simultaneous interactions with a server.
Managed and Unamanaged code/resources
Unmanaged code is directly compiled to machine code and managed code is compiled to IL(intermediate language). Managed code is handled by .Net Framework but unmanaged code is not, there for it is dangerous to yours and others machines.
Unamanaged resources are all those resources that reside out of .Net framework, such as files, memory, database and network connections, or any other scenario outside .Net code.
What happens I do not dispose of connection of a resource?
- Sometimes nothing because Garbage collector will take care of objects, but it is too risky because we do not know when will that event occur.
- OutOfMemoryException exception will occur if Garbage Collector does not free resources because object retains references to resources. In this scenario OutOfMemoryException is thrown before application closes.
Example of implementing using IDisposable and using statement
Lets start by adding a few lined to our text file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
using System.IO; namespace SimpleIDisposableApplication { class Program { static void Main(string[] args) { FileInfo fileInfoInstance = new FileInfo(@"d:\test.txt"); //First we check if file exists if (!fileInfoInstance.Exists) { // if file does not exist we create it // and add a line to it // using StreamWriter StreamWriter streamWriter = fileInfoInstance.CreateText(); streamWriter.WriteLine("Hello World"); } // after we know that file exists // lets try adding a few lines to it // using StreamWriter again for (int i = 0; i < 5; i++) { StreamWriter sw = fileInfoInstance.AppendText(); sw.WriteLine("Line {0}",i); } // Oops // Exception has been thrown: // An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll // Additional information: The process cannot access the file 'd:\test.txt' // because it is being used by another process. } } } |
Error is thrown because there is still opened connection to a file on location d:\test.txt
Lets fix it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System.IO; namespace SimpleIDisposableApplication { class Program { static void Main(string[] args) { FileInfo fileInfoInstance = new FileInfo(@"d:\test.txt"); if (!fileInfoInstance.Exists) { StreamWriter streamWriter = fileInfoInstance.CreateText(); streamWriter.WriteLine("Hello World"); //streamWriter.Dispose(); } for (int i = 0; i < 500; i++) { StreamWriter sw = fileInfoInstance.AppendText(); sw.WriteLine("Line {0}",i); sw.Dispose(); } // Notice we added Dispose() method at the end of for loop // We need to dipose of connection to a file // every time we finish interacting with it // otherwise we get error we saw last time } } } |
What if we wanted to reuse first StreamWriter instance?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
using System.IO; namespace SimpleIDisposableApplication { class Program { static void Main(string[] args) { FileInfo fileInfoInstance = new FileInfo(@"d:\test.txt"); StreamWriter streamWriter = fileInfoInstance.CreateText(); if (!fileInfoInstance.Exists) { streamWriter.WriteLine("Hello World"); } for (int i = 0; i < 500; i++) { StreamWriter sw = fileInfoInstance.AppendText(); sw.WriteLine("Line {0}",i); sw.Dispose(); } // System.IO.IOException is thrown // because we did not dispose of that connection either } } } |
This is tiresome. Is there an easier way to dispose of our connections?
Yes there is, and have mentioned it in previous post. Using statement!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System.IO; namespace SimpleIDisposableApplication { class Program { static void Main(string[] args) { FileInfo fileInfoInstance = new FileInfo(@"d:\test.txt"); using (StreamWriter streamWriter = fileInfoInstance.CreateText()) if (!fileInfoInstance.Exists) { streamWriter.WriteLine("Hello World"); } using (StreamWriter sw = fileInfoInstance.AppendText()) for (int i = 0; i < 500; i++) { sw.WriteLine("Line {0}", i); } } } } |
Adios using Dispose method 🙂
Unless you need to have custom logic added while disposing of your resources. IDisposable will be back in next post.
Leave a Reply