It turns out that AppContext can also get stuck in the MetalLookAndFeel.cachedAppContext static variable. This is addressed by 6482571. Between that fix and this fix, AppContexts should no longer leak for 6u5 (JDK7 requires further investigation).
While profiling this, I noticed that AppContexts also appear to get stuck via JFrame in Java2D's BufferedContext.currentContext. This goes away once Java2D has drawn onto another surface, however it can take a few rounds of GCing for the JFrame/AppContext/WindowDisposerRecord to make it through the J2D Disposer's ReferenceQueue.
This bug presents some interesting problems:
* component and tracker are protected variables in ImageIcon. They are completely undocumented, so why anyone would use them is beyond me, but even so we can't just rip them out of ImageIcon
* component and tracker are also final variables, so we can't, for instance, listen for AppContext disposal and recreate them on a different AppContext.
* We can't sneakily unhook component's appContext reference, as it's package private to java.awt, and we'd be coming from javax.swing. ComponentAccessor might help with this, but that's only in JDK7.
* The ImageIcon spec mentions in several places that it uses MediaTracker to track the loading of images, and in fact returns constants from the MediaTracker class from ImageIcon.getImageLoadStatus(). I don't see being able to move to something such as ImageIO (at least not until JDK 7).
So, our two issues are:
1) Get rid of the ImageIcon->Component->AppContext leak
2) Still track image loading with MediaTracker
(1): I think the path of least risk is to set component and tracker to null. The chances of someone subclassing ImageIcon *and* using these variables for anything seems extremely small.
(2): We could create (and release) a new MediaTracker for every ImageIcon instance, but that could get expensive given that larger apps might load dozens or more ImageIcons. The next best thing is to have a MediaTracker per-AppContext. This cuts way down on the number of MediaTrackers created, and the MediaTracker (and it's Component) would be disposed along with the AppContext, instead of leaking it.