One option is to look at what we can do to help users prepare for IAE when using value-based classes as keys to WHM. Can we take an approach similar to JEP 390 [1] and provide JFR events that flag uses of value-based classes as keys? It's not perfect but similar to JEP 390, it does help users to know if they need to do something to prepare for this.
--Dan [1] http://openjdk.java.net/jeps/390 On Thu, Jan 20, 2022 at 1:54 PM Dan Heidinga <heidi...@redhat.com> wrote: > > > > > It certainly seems that all the choices are bad. > > > > The "obvious" choice is to simply say that WeakReference<Value> makes no > > sense, in that it sidesteps the hard semantics questions. > > It's an uncomfortable answer but it seems to provide the most > defensible (and thus understandable) semantics for users. Values don't > have an explicit lifetime and thus there is no way to tell when "this" > copy of a value goes out of scope and can be collected. The object > references (if any) held by the value are not a good proxy for its > lifecycle - they can have either shorter or much longer life spans - > and will make reasoning about when a WeakReference<Value> can be > collected difficult for experts, let alone most users. > > > My fear is that this will cause new failures, where existing libraries that > > toss objects into WHMs to cache derived results, will start to experience > > new failures when the value types show up in the heap (after all, > > WeakReference::new takes Object.) > > This may be a case where the WeakReference constructor needs to be > updated to take an IdentityObject and the old constructor marked as > @Deprecated? Which doesn't solve the immediate problem but helps > justify adding a "fail-fast" check to all WeakReference constructors > so that they throw an IllegalArgumentException if the referent isn't > an IdentityObject. > > This won't avoid failures but it does make it very clear what went > wrong rather than introducing "strange", hard to diagnose failures. > > > And we'll have to have something to tell those users, because they declared > > a WeakHashMap<User, UserData>, and someone created a value subtype of User > > -- which seems entirely valid. > > > > It is possible we could do something special with WHM, since it is layered > > atop WR, but that still begs the question -- what? > > Starting from the conclusion that WeakReference<Value> is a > meaningless entity, what are the options here? > > 1) Make it impossible to use a Value as a key in a WeakHashMap. > ::put(key, value) & ::pulAll(Map m) will throw if a key is a Value > object. ::containsKey(Object) will always be false if the Object is a > ValueObject. This makes WeakHashMap unusable with Values. The > semantics are clear but all existing uses of WeakHashMap will need to > be adapted to defensively check for Values and do something (tbd) to > avoid the exceptions. > > 2) Use strong references for Value keys in WeakHashMap. > Treat each Value object used as a key in WeakHashMap as a strong > reference. This means Value keys will never be removed and will keep > their corresponding map value alive forever (or until explicitly > removed). While this will allow WeakHashMaps to continue to be used > as Maps for Values, it will break the contract for WHM and may > introduce memory leaks into otherwise correct programs. > > 3) Pick some other object to act as the reference when using a Value > key in a WHM. > This is basically the solution we rejected for WeakReference<Value> > and all the same problems apply here. It may allow existing code to > "keep working" when it first deals with Values but introduces strange > failure cases and difficult to reason about rules. It avoids > exceptions but leaves the code doing the wrong thing with no way to > tell. > > Anyone see another option here? > > --Dan