In the history of bugs
feedback from users of NDepend,
there are 4 unresolved OutOfMemoryException
unhandled. They all have been reported by different users, on different version
of the product and the call stack is different for all of them. The only common
point is that their call stack all begins with: System.Drawing.Graphics.FromHdcInternal(IntPtr hdc). These bugs
have been classified as unreproductible bug so far since we cannot reproduce it
on our machines despite all our efforts and the users can’t reproduce it
For the next version of
NDepend, we are using a new library and suddenly we got once or twice a day
such OutOfMemoryException popping
from FromHdcInternal(…). After crawling the web I found this thread
where several programmers complain for the same problem and after a lot of
ramblings an MSFT conclude by: Bottom
line: make sure you explicitly dispose *all* your Graphics objects.
The problem is then if you
don’t dispose many GDI object (Font, Brush…) you might get such OutOfMemoryException. I also opened my
on this, and Hans Passant explains
that it is likely that the process is running out of GDI handles.
After reverse engineered
the library the next version of NDepend will rely on, I found indeed many undisposed
GDI objects. We are then in the process of tracking unreleased GDI objects in
our code and you know what, it reminds me the (not good) old days when I was programming with C++. Hopefully, I
found the tool .NET Memory Profiler
convenient to track undisposed objects.
Despite our efforts, we
know we won’t get all GDI objects disposed, just because some libraries we are
relying on are and will still leak. To avoid users a bad experience, we will
then add a global catch of all OutOfMemoryException
where the call stack begins with FromHdcInternal.
From a user experience perspective, very rarely some GDI drawing will miss a
detail, not clean but still acceptable. From a programmer perspective such a global catch makes me sick but do we have the choice?
I notice that OutOfMemoryException seems to be the common GDI exception for many problems. When you are tracing a small GDI object, you can get such exception as explained here. I also reported a similar exception to MS (see here) when creating a LinearGradientBrush with the 2 same points. The answer is that because of backward compatibility this can’t be changed.