Caching System.Drawing objects is a mistake. They are very cheap to create, very expensive to keep around. They are allocated on a special heap that all processes on a desktop need to share. The heap size is limited to 65535 objects. Creating objects like a brush or a pen takes roughly a microsecond, miniscule compared to the cost of the operation you perform with them. The only drawing object that is expensive is a Font. Creating one involves a sizable chunk of overhead taken by the font mapper. But that's already solved by .NET, it caches them.
Other than hogging the heap needlessly, the programming style is dangerous. It is far too easy to forget blindly applying the using statement. This certainly can get you into trouble, you are relying on the finalizer thread to release them again. If a program involves lots of heavy painting but not enough object allocation to trigger a GC then you will exhaust the quota for GDI objects. Which is 10,000 objects for a process by default. This will crash your program. Do note that the System.Drawing class wrappers are not nearly big enough to trigger a GC by themselves, 10000 of them will not be enough to get the finalizers to run and release the handles again.
The problem is very easy to diagnose, you can use Task Manager. Use View + Select Columns and tick "GDI Objects". Might as well tick "USER Objects", another one that's very easily leaked. Keep an eye on the displayed counts for your process while you are using it. A steadily climbing number spells doom.