It looks like JUCE used to use pure ref-counting to manage module lifetimes, and the current caching mechanism was added to work around issues with some buggy plugins that weren’t correctly shutting down the Obj-C runtime on when they were unloaded:
I agree the holding onto module handles indefinitely is not a good idea, but we need to test whether removing the global cache breaks some plugins. If it does, then we’d need to weigh up whether it’s more valuable to continue supporting those plugins, or to improve the memory usage of hosts.
