Visitar URL original
fix(reader): reduce reference parsing memory allocations by baywet · Pull Request #3171 · microsoft/OpenAPI.NET · GitHub
Skip to content

fix(reader): reduce reference parsing memory allocations - #3171

Merged
Vincent Biret (baywet) merged 3 commits into
mainfrom
fix/reader-reference-allocations
Nov 13, 2026
Merged

Vincent Biret (baywet) merged 3 commits into
mainfrom
fix/reader-reference-allocations

Conversation

@baywet

Copy link
Copy Markdown
Member

Pull Request

Description

Fix the memory-allocation regression introduced by #3155 while preserving its full JSON pointer paths for nested schema references.

The new per-reference location construction exposed an existing imbalance in named-example location scopes: example locations accumulated across sibling operations, and each schema reference materialized that accumulated history. Balance those scopes and construct a location only when relative-pointer resolution needs it.

This is the independent main-branch port of the performance fixes in #3170, extended to the OpenAPI 3.2 reader available on main.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

Related Issue(s)

Regression introduced by #3155. Corresponding 2.X fixes: #3170.

Changes Made

  • Balance named-example location scopes with try/finally in the OpenAPI 3.0, 3.1, and 3.2 readers. Preserve example-specific diagnostic pointers and restore the caller's location when processing throws.
  • Pass the parsing context to the shared reference-path helper; materialize its location only in the relative-pointer-resolution branch. Keep absolute-pointer comparison/caching behavior and the nested-reference fix unchanged.
  • Add regression coverage for media-type and parameter examples across all three versions, including successful processing, propagated exceptions, and diagnostic errors.
  • Refresh all description and empty-model benchmark reports in a separate chore commit.

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • All existing tests pass

Commands run from the new main-based worktree:

  • dotnet test --project test\Microsoft.OpenApi.Readers.Tests\Microsoft.OpenApi.Readers.Tests.csproj -c Release - passed, 657 tests.
  • dotnet test --project test\Microsoft.OpenApi.Tests\Microsoft.OpenApi.Tests.csproj -c Release -- --filter-class '*Reference*' - passed, 200 tests.
  • dotnet build src\Microsoft.OpenApi\Microsoft.OpenApi.csproj -c Release --no-restore --nologo -v quiet - passed for netstandard2.0 and net8.0, zero warnings/errors.
  • dotnet run -c Release, from performance\benchmark - passed, all 34 benchmarks completed: six description benchmarks and 28 empty-model benchmarks. Verified that every report contains measurements and that all empty-model allocation counts are unchanged.

Formatted the modified files in both changed projects using dotnet format. The full solution/coverage run and trimming validation were not run locally; CI performs those checks.

Checklist

  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Versions applicability

See the contributing guidelines for more information about how patches are applied across multiple versions.

Additional Notes

No public API or documentation changes are required. Version 1.X applicability was not assessed as part of this main-targeted port.

Refreshed allocated memory per parse on .NET 8.0.34 / Windows ARM64:

Benchmark Allocated bytes
GHESYaml 274,351,112
GHESJson 144,657,952
GHESNextYaml 289,530,984
GHESNextJson 162,291,696

These are cumulative managed allocations, not retained document size. Benchmark reports retain their actual machine/runtime metadata; timing comparisons against reports from other machines should not be interpreted as controlled speedup measurements.

Restore parsing locations after named examples, including exception paths, and construct locations only when relative reference resolution requires them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc47aa82-c449-43a1-8a70-c4f3c464ae51
Extend the main-branch port with balanced example scopes, lazy reference locations, and OpenAPI 3.2 regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc47aa82-c449-43a1-8a70-c4f3c464ae51
Regenerate all description and empty-model benchmark reports after porting the reference allocation fixes to main.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc47aa82-c449-43a1-8a70-c4f3c464ae51
@baywet
Vincent Biret (baywet) requested a review from a team as a code owner November 13, 2026 18:29
Copilot AI balanced review requested due to automatic review settings November 13, 2026 18:29
@baywet
Vincent Biret (baywet) enabled auto-merge (squash) November 13, 2026 18:30
@github-code-quality

Copy link
Copy Markdown

Code coverage overview

Languages: C#

C# / code-coverage/dotnet

main d8f20e8 fix/reader-reference... c9179bb +/-
93% 93% 0%
View coverage of the 5 most impacted files.
File main d8f20e8 fix/reader-reference... c9179bb +/-
/home/runner/wo...Deserializer.cs 100% 100% 0%
/home/runner/wo...Deserializer.cs 100% 100% 0%
/home/runner/wo...Deserializer.cs 79% 81% +2%
/home/runner/wo...Deserializer.cs 69% 72% +3%
/home/runner/wo...Deserializer.cs 69% 72% +3%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues remain for the OpenAPI reader allocation optimizations.

No open issues 🎉

What changed in this PR

Reduces OpenAPI reader allocations while preserving the full nested-schema reference paths introduced by #3155 across OpenAPI 3.0, 3.1, and 3.2.

Changes:

  • Builds location strings only when relative-pointer resolution needs them.
  • Balances named-example location scopes, with regression tests for successful parsing, exceptions, and diagnostic pointers.
  • Refreshes parsing and empty-model benchmark reports with actual machine/runtime metadata.
File Description
test/​Microsoft.OpenApi.Readers.Tests/​V32Tests/​OpenApiDynamicRefTests.cs Adapts the 3.2 dynamic-reference test to the context-based helper.
test/​Microsoft.OpenApi.Readers.Tests/​V31Tests/​OpenApiDynamicRefTests.cs Adapts the 3.1 dynamic-reference test to the context-based helper.
test/​Microsoft.OpenApi.Readers.Tests/​ParsingContextTests.cs Tests example-scope cleanup and diagnostic locations across all three versions.
src/​Microsoft.OpenApi/​Reader/​V32/​OpenApiV32Deserializer.cs Balances 3.2 example scopes and preserves error pointers.
src/​Microsoft.OpenApi/​Reader/​V32/​OpenApiSchemaDeserializer.cs Passes parsing context for deferred reference-location construction.
src/​Microsoft.OpenApi/​Reader/​V31/​OpenApiV31Deserializer.cs Balances 3.1 example scopes and preserves error pointers.
src/​Microsoft.OpenApi/​Reader/​V31/​OpenApiSchemaDeserializer.cs Passes parsing context for deferred reference-location construction.
src/​Microsoft.OpenApi/​Reader/​V3/​OpenApiV3Deserializer.cs Balances 3.0 example scopes and preserves error pointers.
src/​Microsoft.OpenApi/​Reader/​V3/​OpenApiSchemaDeserializer.cs Avoids eagerly constructing schema-reference locations.
src/​Microsoft.OpenApi/​Models/​BaseOpenApiReference.cs Materializes locations only for relative-pointer resolution.
performance/​benchmark/​BenchmarkDotNet.Artifacts/​results/​performance.EmptyModels-report.html Refreshes the HTML empty-model benchmark report.
performance/​benchmark/​BenchmarkDotNet.Artifacts/​results/​performance.EmptyModels-report.csv Refreshes CSV measurements; allocation counts remain unchanged.
performance/​benchmark/​BenchmarkDotNet.Artifacts/​results/​performance.EmptyModels-report-github.md Refreshes the Markdown empty-model benchmark summary.
performance/​benchmark/​BenchmarkDotNet.Artifacts/​results/​performance.Descriptions-report.json Updates detailed parsing measurements and environment metadata.
performance/​benchmark/​BenchmarkDotNet.Artifacts/​results/​performance.Descriptions-report.html Refreshes the HTML parsing benchmark report.
performance/​benchmark/​BenchmarkDotNet.Artifacts/​results/​performance.Descriptions-report.csv Refreshes machine-readable parsing benchmark measurements.
performance/​benchmark/​BenchmarkDotNet.Artifacts/​results/​performance.Descriptions-report-github.md Refreshes the Markdown parsing benchmark summary.

Review effort: Balanced

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
18.7% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@baywet
Vincent Biret (baywet) merged commit d14d0a1 into main Nov 13, 2026
19 of 20 checks passed
@baywet
Vincent Biret (baywet) deleted the fix/reader-reference-allocations branch November 13, 2026 18:47
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.

3 participants