Skip to content

SONARJAVA-7189 Do not allocate lambdas on cache hits in JSema - #6362

Merged
aurelien-coet-sonarsource merged 2 commits into
masterfrom
ac/SONARJAVA-7189
Oct 15, 2026
Merged

aurelien-coet-sonarsource merged 2 commits into
masterfrom
ac/SONARJAVA-7189

Conversation

@aurelien-coet-sonarsource

@aurelien-coet-sonarsource aurelien-coet-sonarsource commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary by Gitar

  • Performance:
    • Added get fast paths before computeIfAbsent in type, typeSymbol, methodSymbol, variableSymbol, annotation, and getClassType in JSema
    • Lambdas are no longer allocated when the cache already holds the requested binding
  • Lambda capture:
    • type now passes the lambda parameter k instead of capturing typeBinding
  • Initializer caching:
    • Added get fast paths in packageSymbol, initializerBlockSymbol, and staticInitializerBlockSymbol in JSema
    • Initializer block lambdas now pass the parameter k instead of capturing owner

This will update automatically on new commits.

@aurelien-coet-sonarsource
aurelien-coet-sonarsource added this pull request to stack #6363 October 15, 2026 09:35
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

SONARJAVA-7189

@aurelien-coet-sonarsource

Copy link
Copy Markdown
Contributor Author

Bechmark:

To assess the impact of the changes in this PR, a benchmark on a sample project (the core module in jOOQ) analyzed the same 2,127 Java files with identical rules and settings. Each version had ten measured scans at both 2 GB and 4 GB heaps, using fresh JVMs, plus three separate 4 GB Java Flight Recorder allocation profiles. Warmups were excluded. JFR estimated allocation volume, GC logs measured collection activity, and process sampling tracked CPU and peak RSS. The results below are medians.

Results:

Adding cache-hit checks before creating lambdas in JSema substantially reduced allocation traffic. Compared with the version already using loops in override searches and method matchers:

Median per scan Before After Change
Total allocation 82.39 GB 76.76 GB −6.8%
JSema lambda allocation 6.084 GB 0.045 GB −99.3%
Java analysis, 2 GB heap 101.1 s 96.2 s −4.8%
Java analysis, 4 GB heap 93.2 s 90.6 s −2.7%

GC pause time decreased by 13.5% at 2 GB and 12.1% at 4 GB, while peak RSS remained essentially unchanged. The optimization primarily reduced temporary allocations and collection work.

All scans produced identical analysis results, and only JSema.class differed between the plugins.

@aurelien-coet-sonarsource
aurelien-coet-sonarsource marked this pull request as ready for review October 15, 2026 11:36
Base automatically changed from ac/SONARJAVA-6910 to master October 15, 2026 12:20
@gitar-bot

gitar-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Code Review ✅ Approved 1 closed / 1 findings

🟢 Low risk · These localized JSema cache fast paths avoid lambda allocation on cache hits, with no public interface or semantic-model behavior change indicated.

Adds get fast paths before computeIfAbsent across JSema lookups so cache hits no longer allocate lambdas, and type and initializer-block lambdas now take the key parameter instead of capturing outer variables. The previously flagged capturing lambda on initializer-block lookup hits has been addressed. No open issues found.

✅ 1 closed
✅ Quality: Initializer-block lookups still allocate a capturing lambda on each hit

📄 java-frontend/src/main/java/org/sonar/java/model/JSema.java:104-110
The PR is meant to stop allocating lambdas on cache hits in JSema, but initializerBlockSymbol and staticInitializerBlockSymbol were not changed. Their lambdas capture owner (k -> new JInitializerBlockSymbol(owner, false/true)), so every call allocates a new lambda instance, even when the symbol is already cached. That is the same pattern the PR removes from the other seven lookup methods. To fix it, add the same get fast path to both methods, and make the lambdas use k instead of owner so they no longer capture anything.

Verification Rules 1/1 met PRs 2 inspected

Functional validation No results

Rules 1 passed 2 not applicable

✅ Repository license compliance

Broader impact PRs 2 inspected
Cross-PR 2 PRs inspected 0 open impacts

PR #6349: SONARJAVA-7182 Replace frequently allocated streams with loops Inspected
PR #6308: SONARJAVA-7137 Optionally rely on source paths to resolve types during analyses Inspected

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@vdiez vdiez left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sonarqube-next

Copy link
Copy Markdown
Contributor

@aurelien-coet-sonarsource
aurelien-coet-sonarsource merged commit 5778942 into master Oct 15, 2026
19 checks passed
@aurelien-coet-sonarsource
aurelien-coet-sonarsource deleted the ac/SONARJAVA-7189 branch October 15, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants