RFR: 8309688: Data race on java.io.ClassCache$CacheRef.strongReferent [v2]
Aleksey Shipilev
shade at openjdk.org
Tue Jun 13 19:47:51 UTC 2023
On Tue, 13 Jun 2023 19:24:08 GMT, Man Cao <manc at openjdk.org> wrote:
>> Hi all,
>>
>> Could anyone review this small fix for a data race in java.io.ClassCache$CacheRef? This fix makes the code safer by making the code data-race-free.
>
> Man Cao has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains two additional commits since the last revision:
>
> - Merge branch 'master' into JDK8309688
> - 8309688: Data race on java.io.ClassCache.strongReferent
I think this data race is benign, because `ClassValue` gives us the required memory semantics. Introducing additional performance hogs seems weird in this case, see below.
Since TSAN complains about the unsynchronized conflicting accesses in `getStrong()` and `clearStrong()`, maybe the better solution would be marking `strong` as `volatile`? It would still be awkward, but we would "only" pay a price of volatile load on a hot path.
src/java.base/share/classes/java/io/ClassCache.java line 43:
> 41: private static class CacheRef<T> extends SoftReference<T> {
> 42: private final Class<?> type;
> 43: private final AtomicReference<T> strongReferent;
This introduces a dereference and additional `AR` instance per `CacheRef`. Maybe it should be `AtomicReferenceFieldUpdater` or a `VarHandle`, assuming there are no bootstrapping issues with this code.
src/java.base/share/classes/java/io/ClassCache.java line 87:
> 85: // This guarantees progress for at least one thread on every CacheRef.
> 86: // Clear the strong referent before returning to make the cache soft.
> 87: T strongVal = ref.getAndClearStrong();
This is a cache, so IIRC, the prevailing case is when CacheRef already exists in the map, and its `strong` is already `null`. So this change introduces an atomic op, which is mostly useless on this path. So we pay a latency price on most `get()`-s without much benefit.
-------------
Changes requested by shade (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/14386#pullrequestreview-1477926122
PR Review Comment: https://git.openjdk.org/jdk/pull/14386#discussion_r1228605313
PR Review Comment: https://git.openjdk.org/jdk/pull/14386#discussion_r1228607613
More information about the core-libs-dev
mailing list