From examining the code for java.util.ResourceBundle (circa JDK 1.3) it seems that it holds onto both bundle values and classloader keys using soft references. For the bundle values, this definitely makes sense--parsing bundles takes time and they should be cached, but they can be reloaded if memory requirements make that necessary. But I do not understand why the classloader is held (by ResourceBundle.ResourceCacheKey.loaderRef) as a soft reference. Wouldn't a weak reference be better?
For example, create some classloader; load a bundle through that classloader and use some messages in it; now discard all references to the bundle *and* to the classloader. The classloader cannot now be garbage-collected because ResourceBundle is still holding onto it (until the system runs out of memory, I guess), as I found out using a heap analyzer: I had managed to clear all references to some old classloaders except for those held by ResourceBundle. (If the loader ref were a WeakReference, then after a normal GC the unused classloader should be released.) There is no reason I can think of to cache bundles from the now softly-referenced classloader since no one else even has a handle on it.
Affected also by #4405789 which says that JAR files are not reloadable in new URLClassLoader's until old ones are GC'd. With ResourceBundle holding onto the old loaders it is impossible to GC the old ones reliably, and thus very difficult to reload JARs into a running application, as well as leaking some memory.
Observed on RedHat Linux with JDK 1.3 FCS. Affects NetBeans/Forte for Java application (dynamic reloadability of plug-in modules).