Skip to content

Use String keys in UrlJarFiles cache to avoid HashMap.getNode type profile pollution - #51145

Closed
waterWang wants to merge 1 commit into
spring-projects:mainfrom
waterWang:fix-jarfileurlkey-perf-regression
Closed

Use String keys in UrlJarFiles cache to avoid HashMap.getNode type profile pollution#51145
waterWang wants to merge 1 commit into
spring-projects:mainfrom
waterWang:fix-jarfileurlkey-perf-regression

Conversation

@waterWang

Copy link
Copy Markdown

Summary

This commit fixes the performance regression described in #51141.

Problem

Commit 08cc62a changed the loader cache from Map<String, JarFile> to Map<JarFileUrlKey, JarFile>. A new JarFileUrlKey value object is allocated on every cache lookup, polluting the JVM-wide shared HashMap.getNode C2 type profile. This causes the method to go megamorphic, so C2 stops devirtualizing/inlining equals() / hashCode() — degrading unrelated application HashMap<String,...> / HashMap<Integer,...> lookups on hot code paths.

Before the commit the cache key was a String (the same type applications commonly use), so the shared profile stayed mono/bimorphic.

Fix

  1. Added JarFileUrlKey.toKeyString() — produces a unique string representation without triggering DNS lookups (preserves the original DNS-avoidance behavior)
  2. Changed the internal Cache map from Map<JarFileUrlKey, JarFile> to Map<String, JarFile>
  3. Cache operations use new JarFileUrlKey(url).toKeyString() as the key

Since HashMap.getNode is now called with String keys, the shared type profile is no longer polluted by the custom key type, and application HashMap.get() calls remain optimized.

Verification

The JarFileUrlKeyTests test class covers the key equality semantics. Cache behavior is unchanged — the same JarFileUrlKey fields are used to derive the key string, so cache hit/miss semantics are identical.

Closes #51141

Replace Map<JarFileUrlKey, JarFile> with Map<String, JarFile> in the
loader cache. The custom JarFileUrlKey value object was allocated on
every cache lookup, polluting the JVM-wide shared HashMap.getNode
C2 type profile. This caused the method to go megamorphic,
deoptimizing unrelated application HashMap.get() calls on hot code
paths.

The fix adds JarFileUrlKey.toKeyString() which produces a unique
string representation without triggering DNS lookups, and changes
the underlying cache map to use String keys. The DNS-avoidance
behavior is preserved.

See spring-projectsgh-51141.

Closes spring-projectsgh-51141.
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 29, 2026
@snicoll

snicoll commented Jul 30, 2026

Copy link
Copy Markdown
Member

Thanks for the PR but I am not quite sure that the benchmark in the related issue holds. This change ads adds string allocation overhead and degrades equality semantics so we wouldn't pursue either way.

@snicoll snicoll closed this Jul 30, 2026
@snicoll snicoll added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: declined A suggestion or change that we don't feel we should currently apply

Projects

None yet

3 participants