Don't blame the JVM, it's the library! The API for java.awt.Toolkit.getImage states:
The underlying toolkit attempts to resolve multiple requests with the same filename to the same returned Image. Since the mechanism required to facilitate this sharing of Image objects may continue to hold onto images that are no longer of use for an indefinite period of time, developers are encouraged to implement their own caching of images by using the createImage variant wherever available.
The documentation in javax.swing.ImageIcon doesn't reveal all, but the constructors that are passed a URL or a filename
string use Toolkit's getImage in all the source code from Sun I've read.
Advice: avoid Toolkit's getImage, and the ImageIcon constructors that take a filename string or URL. I'd like to learn the JAIm but it keeps getting bumped down my to-do list (work, *sigh*), however reading images with javax.imageio.ImageIO is a snap, and there is no caching:
BufferedImage is a subclass of Image. There's no need to use MediaTracker or ImageObserver with it -- its pixels are always in memory.