In this post, I’ll talk about some issues that one must understand about mixing finalization and P/Invoke Interoping.
Usually, when you have a class that has an IntPtr as a member due to some P/Invoke code you implement a Finalizer and the IDisposable interface in which the necessary cleanup code will be implemented to release the unmanaged resources you have allocated.
The main problem starts when that same class has other member variables that are managed.
These managed member variables will not get collected until our class’ instance is finalized and that can generate memory pressure that is not really necessary if things are implemented correctly.
So, what can we do about it?
There are a few approaches that can help us minimize the effect of P/Invoking and finalizers:
- Don’t declare the IntPtr variable as a member variable.
- Create a class that wraps the IntPtr and P/Invoke code without declaring managed member variables.
Let’s examine both approaches.
The first approach talks about not declaring IntPtr variables as member variables. This means that if you have some function that needs to interop, delcare the IntPtr variable as a local variable, use it and clean everything up. This is the best approach but will only work if there are no (serious) performance penalties such as calling some heavy P/Invoked Windows API.
The second approach is a more viable one if there is a need to continuously call some unmanaged API such as ReadFile on a socket or file. In this case, writing a dedicated class that holds the reference to the unmanaged resource only and a finalizer and IDisposable would be a great way of making sure that it will not hold back the GC of other resources (not to mention it would be cleaner to have a dedicated class for wrapping such API ).
That class we have an IntPtr as a member variable and will have additional functions to manipulate the data that is being held behind that unmanaged resource.
By implementing one of the two approaches I’ve discussed above you can, quite easily, ease the memory pressure on your application with little change to your code and functionality.
In .NET Framework 2.0 that will come with Visual Studio 2005 (formerly known as Whideby) there is a new mechanism to handle such issues called SafeHandle. You can read more about it here, in this great post from the BCL Team Blog.
I will talk about SafeHandles in a subsequent post.