Skip to content

Fix Path.Data and Path.RenderTransform visual tree leaks with shared resources - #36097

Merged
kubaflo merged 2 commits into
dotnet:inflight/currentfrom
devanathan-vaithiyanathan:fix-34860
Jun 24, 2026
Merged

Fix Path.Data and Path.RenderTransform visual tree leaks with shared resources#36097
kubaflo merged 2 commits into
dotnet:inflight/currentfrom
devanathan-vaithiyanathan:fix-34860

Conversation

@devanathan-vaithiyanathan

@devanathan-vaithiyanathan devanathan-vaithiyanathan commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment whether this change resolves your issue. Thank you!

Issue Details

Path.Data and Path.RenderTransform can cause memory leaks when they use shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding context data may also be retained.This is reproducible across platforms.

Description of Change

Added weak-event subscription handling so Path no longer holds strong references through shared geometry/transform change events.

Issues Fixed

Fixes #35860

Tested the behavior in the following platforms.

  • Android
  • Windows
  • iOS
  • Mac
Before After
iOS
Before.mov
iOS
After.mov

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36097

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36097"

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Jun 24, 2026
@github-actions github-actions Bot added the area-drawing Shapes, Borders, Shadows, Graphics, BoxView, custom drawing label Jun 24, 2026
@sheiksyedm
sheiksyedm marked this pull request as ready for review June 24, 2026 11:28
@sheiksyedm sheiksyedm added the community ✨ Community Contribution label Jun 24, 2026
@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 24, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 1 findings

See inline comments for details.

{
}

~Path()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[major] Public API Surface / Build — Adding a destructor to public Path introduces a new finalizer API entry, but the PR does not update the Controls PublicAPI.Unshipped.txt baselines. The shipped API files already track destructors for Shape, Border, and other public types, so API validation is likely to fail for Microsoft.Maui.Controls.Shapes.Path.~Path() -> void on each target. Either add the new destructor entries to the appropriate src/Controls/src/Core/PublicAPI/*/PublicAPI.Unshipped.txt files, or avoid introducing a Path finalizer by moving the cleanup to an already-finalized base/type-level cleanup pattern.

@MauiBot MauiBot added s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jun 24, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

@devanathan-vaithiyanathan — new AI review results are available based on this last commit: c94dcd9. To request a fresh review after new comments or commits, comment /review rerun.

Gate Passed Confidence Low Platform iOS


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: IOS · Base: main · Merge base: 19abc43e

Test Without Fix (expect FAIL) With Fix (expect PASS)
🧪 PathSharedResourcesMemoryLeakTests PathSharedResourcesMemoryLeakTests ✅ FAIL — 35s ✅ PASS — 18s
🔴 Without fix — 🧪 PathSharedResourcesMemoryLeakTests: FAIL ✅ · 35s
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 754 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/TestUtils/TestUtils.csproj (in 5.6 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 6.14 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj (in 6.14 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 6.65 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/maps/src/Maps.csproj (in 6.65 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 6.65 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 6.65 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 6.66 sec).
  1 of 10 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  TestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
  Controls.Core.UnitTests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.07]   Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:00.55]   Discovered:  Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:00.55]   Starting:    Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:00.61]     SharedGeometryAndTransform_DoNotKeepPathAlive [FAIL]
[xUnit.net 00:00:00.61]       Path was not collected. Shared PathGeometry and/or ScaleTransform are holding strong references to Path via event subscriptions. Use weak proxies to fix.
[xUnit.net 00:00:00.61]       Stack Trace:
[xUnit.net 00:00:00.61]         /_/src/Controls/tests/Core.UnitTests/Shapes/PathSharedResourcesMemoryLeakTests.cs(108,0): at Microsoft.Maui.Controls.Core.UnitTests.Shapes.PathSharedResourcesMemoryLeakTests.SharedGeometryAndTransform_DoNotKeepPathAlive()
[xUnit.net 00:00:00.61]            at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
[xUnit.net 00:00:00.61]            at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
[xUnit.net 00:00:00.61]     SharedRenderTransform_DoesNotKeepPathAlive [FAIL]
[xUnit.net 00:00:00.61]       Path was not collected. The shared ScaleTransform is holding a strong reference to Path via its PropertyChanged event handler. Use WeakNotifyPropertyChangedProxy to fix.
[xUnit.net 00:00:00.61]       Stack Trace:
[xUnit.net 00:00:00.61]         /_/src/Controls/tests/Core.UnitTests/Shapes/PathSharedResourcesMemoryLeakTests.cs(76,0): at Microsoft.Maui.Controls.Core.UnitTests.Shapes.PathSharedResourcesMemoryLeakTests.SharedRenderTransform_DoesNotKeepPathAlive()
[xUnit.net 00:00:00.61]            at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
[xUnit.net 00:00:00.61]            at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
[xUnit.net 00:00:00.61]     SharedPathGeometry_DoesNotKeepPathAlive [FAIL]
[xUnit.net 00:00:00.61]       Path was not collected. The shared PathGeometry is holding a strong reference to Path via its PropertyChanged event handler. Use WeakGeometryChangedProxy to fix.
[xUnit.net 00:00:00.61]       Stack Trace:
[xUnit.net 00:00:00.61]         /_/src/Controls/tests/Core.UnitTests/Shapes/PathSharedResourcesMemoryLeakTests.cs(57,0): at Microsoft.Maui.Controls.Core.UnitTests.Shapes.PathSharedResourcesMemoryLeakTests.SharedPathGeometry_DoesNotKeepPathAlive()
[xUnit.net 00:00:00.61]            at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
[xUnit.net 00:00:00.61]            at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
[xUnit.net 00:00:00.61]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
  Failed SharedGeometryAndTransform_DoNotKeepPathAlive [19 ms]
  Error Message:
   Path was not collected. Shared PathGeometry and/or ScaleTransform are holding strong references to Path via event subscriptions. Use weak proxies to fix.
  Stack Trace:
     at Microsoft.Maui.Controls.Core.UnitTests.Shapes.PathSharedResourcesMemoryLeakTests.SharedGeometryAndTransform_DoNotKeepPathAlive() in /_/src/Controls/tests/Core.UnitTests/Shapes/PathSharedResourcesMemoryLeakTests.cs:line 108
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
  Failed SharedRenderTransform_DoesNotKeepPathAlive [7 ms]
  Error Message:
   Path was not collected. The shared ScaleTransform is holding a strong reference to Path via its PropertyChanged event handler. Use WeakNotifyPropertyChangedProxy to fix.
  Stack Trace:
     at Microsoft.Maui.Controls.Core.UnitTests.Shapes.PathSharedResourcesMemoryLeakTests.SharedRenderTransform_DoesNotKeepPathAlive() in /_/src/Controls/tests/Core.UnitTests/Shapes/PathSharedResourcesMemoryLeakTests.cs:line 76
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
  Failed SharedPathGeometry_DoesNotKeepPathAlive [5 ms]
  Error Message:
   Path was not collected. The shared PathGeometry is holding a strong reference to Path via its PropertyChanged event handler. Use WeakGeometryChangedProxy to fix.
  Stack Trace:
     at Microsoft.Maui.Controls.Core.UnitTests.Shapes.PathSharedResourcesMemoryLeakTests.SharedPathGeometry_DoesNotKeepPathAlive() in /_/src/Controls/tests/Core.UnitTests/Shapes/PathSharedResourcesMemoryLeakTests.cs:line 57
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Test Run Failed.
Total tests: 3
     Failed: 3
 Total time: 0.8880 Seconds

🟢 With fix — 🧪 PathSharedResourcesMemoryLeakTests: PASS ✅ · 18s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14473038
  Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  TestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
  Controls.Core.UnitTests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.07]   Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:00.61]   Discovered:  Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:00.62]   Starting:    Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:00.66]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
  Passed SharedGeometryAndTransform_DoNotKeepPathAlive [14 ms]
  Passed SharedRenderTransform_DoesNotKeepPathAlive [4 ms]
  Passed SharedPathGeometry_DoesNotKeepPathAlive [4 ms]

Test Run Successful.
Total tests: 3
     Passed: 3
 Total time: 0.9303 Seconds

📁 Fix files reverted (2 files)
  • src/Controls/src/Core/Internals/WeakEventProxy.cs
  • src/Controls/src/Core/Shapes/Path.cs

📋 Pre-Flight — Context & Validation

Issue: #35860 - Path.Data / Path.RenderTransform leaks Path visual trees when using shared app-level PathGeometry or ScaleTransform
PR: #36097 - Fix Path.Data and Path.RenderTransform visual tree leaks with shared resources
Platforms Affected: iOS, Android; managed Controls fix is cross-platform
Files Changed: 2 implementation, 1 test

Key Findings

  • Root cause: long-lived shared PathGeometry / ScaleTransform resources strongly retained transient Path instances through event subscriptions.
  • PR fix: weak-event subscription handling for Path.Data and Path.RenderTransform, plus unit tests for shared geometry/transform GC collection.
  • Public issue reproduction reports 1200 retained Path instances and 200 MB retained payload after 50 iOS navigation cycles; validation comments also reproduce on iOS and Android.
  • GitHub CLI was unauthenticated, so context gathering used local branch diff and public GitHub API; authenticated CI/AzDO details were unavailable.

Code Review Summary

Verdict: NEEDS_DISCUSSION
Confidence: low
Errors: 0 | Warnings: 2 | Suggestions: 1

Key code review findings:

  • ⚠️ WeakGeometryChangedProxy in WeakEventProxy.cs couples shared weak-event infrastructure to Shapes; a nested Path proxy would match existing scoping precedent.
  • ⚠️ One EventHandler callback handles both PropertyChanged and InvalidatePathGeometryRequested; valid but less obvious for maintainers.
  • 💡 Existing tests do not explicitly cover Data reassignment from one shared geometry to another.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #36097 Adds WeakGeometryChangedProxy to shared WeakEventProxy.cs and uses weak proxies from Path.cs ✅ PASSED (Gate) WeakEventProxy.cs, Path.cs, unit tests Original PR

🔬 Code Review — Deep Analysis

Code Review — PR #36097

Independent Assessment

What this changes: Path.cs replaces direct strong-reference event subscriptions on Geometry.PropertyChanged, PathGeometry.InvalidatePathGeometryRequested, and Transform.PropertyChanged with weak-reference proxy subscriptions. WeakEventProxy.cs gains WeakGeometryChangedProxy. Unit tests verify that shared PathGeometry and ScaleTransform resources do not keep transient Path instances alive.

Inferred motivation: Shared app-level geometry/transform resources can live for the application lifetime. When they store instance event handlers from transient Path controls, the shared resource strongly roots the old Path, its page graph, and binding-context payload after navigation.

Reconciliation with PR Narrative

Author claims: Shared PathGeometry / ScaleTransform resources keep Path alive via strong event subscriptions; the fix uses weak-event subscription handling; tested on Android, Windows, iOS, and Mac.

Agreement/disagreement: The code matches the described root cause and fix. Platform testing claims could not be independently verified because GitHub CLI/AzDO auth was unavailable.

Prior Review Reconciliation

Prior ❌ Error Finding Source Status Evidence

No prior ❌ Error findings found from public PR comments or inline review comments.

Blast Radius Assessment

  • Runs for all instances: no; subscriptions are created only when Path.Data or Path.RenderTransform is non-null.
  • Startup impact: no static startup path is introduced.
  • Static/shared state: none; proxy fields are per-Path instance.

CI Status

  • Required-check result: undetermined locally; gh was unauthenticated.
  • Classification: undetermined.
  • Action taken: confidence capped because required checks could not be queried through authenticated tooling.

Findings

⚠️ Warning — WeakGeometryChangedProxy placement couples shared weak-event infrastructure to Shapes

WeakEventProxy.cs is general Controls infrastructure, but the PR adds using Microsoft.Maui.Controls.Shapes and a geometry-specific proxy there. The analogous brush proxy is scoped near its consumer (Shape.WeakBrushChangedProxy), so a nested Path proxy would reduce blast radius.

⚠️ Warning — Shared callback signature obscures PropertyChangedEventArgs

WeakGeometryChangedProxy.OnGeometryChanged(object?, EventArgs) is subscribed to both PropertyChanged and InvalidatePathGeometryRequested. This is valid method-group variance and behaviorally correct, but less obvious to maintainers than a typed property-changed proxy plus a separate invalidate proxy or an explanatory scoped implementation.

💡 Suggestion — Add reassignment regression coverage

The existing tests cover collection after assigning shared geometry, transform, and both. A reassignment test would explicitly cover unsubscribe-from-old/subscribe-to-new behavior.

Failure-Mode Probing

  • Shared resource outlives Path: weak proxy prevents the resource from strongly rooting the Path delegate.
  • Data or RenderTransform set to null: propertyChanging unsubscribes before the new null value is applied.
  • Same resource assigned twice: proxy Subscribe unsubscribes from the previous source before re-subscribing.
  • Multiple paths share one geometry: each path has an independent proxy and dead proxies self-unsubscribe on finalizer/event callback.

Verdict: NEEDS_DISCUSSION

Confidence: low
Summary: The PR's functional fix appears mechanically correct and the gate result supplied by the caller passed. The main review concern is maintainability/layering: the geometry-specific proxy can be scoped to Path.cs without changing behavior.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix Nested WeakGeometryChangedProxy inside Path.cs; no Shapes dependency in WeakEventProxy.cs ✅ PASS 1 implementation file (+ tests retained) Behavior-equivalent to PR, better layering/lower blast radius
PR PR #36097 Top-level WeakGeometryChangedProxy in WeakEventProxy.cs plus Path.cs weak proxy usage ✅ PASSED (Gate) 2 implementation files + tests Original PR

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 1 Yes Candidate A nested proxy, Candidate B split proxies, Candidate C handler lifecycle, Candidate D CWT relay, Candidate E Window hook
orchestrator 1 Stop Candidate 1 passed all targeted tests and is demonstrably better than the PR fix because it removes the shared-infrastructure layer violation while preserving behavior

Exhausted: No — stopped by pass-and-better criterion.
Selected Fix: Candidate #1 — It passes the targeted regression tests and improves the PR's maintainability by scoping geometry-specific weak-event behavior to Path.cs instead of WeakEventProxy.cs.


🏁 Report — Final Recommendation

Comparative Candidate Report — PR #36097

Candidates compared

Candidate Approach Regression result Review/build risk Rank
pr-plus-reviewer Keeps the PR weak-event implementation and adds missing Path finalizer PublicAPI unshipped entries in all Controls API baselines. ✅ Passed supplied gate by inheritance from PR fix. ✅ Addresses the expert reviewer's major API baseline finding. 1
try-fix-1 Moves WeakGeometryChangedProxy into Path.cs, keeping geometry-specific weak-event logic scoped to its only consumer while using WeakNotifyPropertyChangedProxy for transforms. ✅ Passed targeted regression tests. ⚠️ Better layering than PR, but the STEP 5a candidate does not include the required Path.~Path() PublicAPI entries; its recorded diff also contains unrelated HybridWebView.js noise, making it less merge-ready as submitted. 2
pr Adds top-level WeakGeometryChangedProxy in shared weak-event infrastructure and uses weak proxies from Path.cs. ✅ Passed supplied gate. ❌ Missing finalizer PublicAPI unshipped entries flagged by expert review; also has a lower-severity layering concern because shared weak-event infrastructure imports Shapes. 3

Analysis

All behaviorally relevant candidates fix the root leak mechanism: shared long-lived PathGeometry and ScaleTransform resources no longer strongly retain transient Path instances through event subscriptions. None of the candidates failed the supplied regression tests, so ranking is determined by completeness and merge risk.

try-fix-1 has the cleanest layering because it scopes geometry-specific event proxy logic inside Path.cs instead of coupling WeakEventProxy.cs to Shapes. However, as a STEP 5a candidate it lacks the required PublicAPI baseline entries for the newly introduced Path finalizer, and its recorded candidate diff includes unrelated generated HybridWebView.js changes. Those issues make it less safe to select as the single winning candidate.

pr passes the leak gate but is incomplete after expert review because API validation is likely to fail for Microsoft.Maui.Controls.Shapes.Path.~Path() -> void.

pr-plus-reviewer keeps the PR's tested behavior and applies the expert reviewer's actionable API baseline fix. Although it preserves the PR's lower-severity layering tradeoff, it is the most complete and lowest-risk candidate among the actual candidate set.

Winner

pr-plus-reviewer

It is the only candidate that both preserves the passing regression fix and incorporates the expert reviewer's required API baseline correction.


🧭 Next Steps — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 24, 2026
@kubaflo
kubaflo changed the base branch from main to inflight/current June 24, 2026 22:17
@kubaflo
kubaflo merged commit 7cb6e69 into dotnet:inflight/current Jun 24, 2026
34 of 37 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR9 milestone Jun 24, 2026
kubaflo pushed a commit that referenced this pull request Jun 25, 2026
…resources (#36097)

<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
Path.Data and Path.RenderTransform can cause memory leaks when they use
shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event
subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding
context data may also be retained.This is reproducible across platforms.

### Description of Change

<!-- Enter description of the fix in this section -->
Added weak-event subscription handling so Path no longer holds strong
references through shared geometry/transform change events.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35860 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/5bbfab0e-1978-46f9-91e2-a93b5b037ced"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/98c362a0-a10e-411b-91b6-d612105958a2"
width="300" height="600"> |
kubaflo pushed a commit that referenced this pull request Jul 3, 2026
…resources (#36097)

<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
Path.Data and Path.RenderTransform can cause memory leaks when they use
shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event
subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding
context data may also be retained.This is reproducible across platforms.

### Description of Change

<!-- Enter description of the fix in this section -->
Added weak-event subscription handling so Path no longer holds strong
references through shared geometry/transform change events.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35860 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/5bbfab0e-1978-46f9-91e2-a93b5b037ced"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/98c362a0-a10e-411b-91b6-d612105958a2"
width="300" height="600"> |
@kubaflo kubaflo mentioned this pull request Jul 6, 2026
kubaflo pushed a commit that referenced this pull request Jul 6, 2026
…resources (#36097)

<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
Path.Data and Path.RenderTransform can cause memory leaks when they use
shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event
subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding
context data may also be retained.This is reproducible across platforms.

### Description of Change

<!-- Enter description of the fix in this section -->
Added weak-event subscription handling so Path no longer holds strong
references through shared geometry/transform change events.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35860 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/5bbfab0e-1978-46f9-91e2-a93b5b037ced"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/98c362a0-a10e-411b-91b6-d612105958a2"
width="300" height="600"> |
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…resources (#36097)

<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
Path.Data and Path.RenderTransform can cause memory leaks when they use
shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event
subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding
context data may also be retained.This is reproducible across platforms.

### Description of Change

<!-- Enter description of the fix in this section -->
Added weak-event subscription handling so Path no longer holds strong
references through shared geometry/transform change events.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35860 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/5bbfab0e-1978-46f9-91e2-a93b5b037ced"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/98c362a0-a10e-411b-91b6-d612105958a2"
width="300" height="600"> |
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…resources (#36097)

<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
Path.Data and Path.RenderTransform can cause memory leaks when they use
shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event
subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding
context data may also be retained.This is reproducible across platforms.

### Description of Change

<!-- Enter description of the fix in this section -->
Added weak-event subscription handling so Path no longer holds strong
references through shared geometry/transform change events.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35860 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/5bbfab0e-1978-46f9-91e2-a93b5b037ced"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/98c362a0-a10e-411b-91b6-d612105958a2"
width="300" height="600"> |
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
…resources (#36097)

<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
Path.Data and Path.RenderTransform can cause memory leaks when they use
shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event
subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding
context data may also be retained.This is reproducible across platforms.

### Description of Change

<!-- Enter description of the fix in this section -->
Added weak-event subscription handling so Path no longer holds strong
references through shared geometry/transform change events.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35860 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/5bbfab0e-1978-46f9-91e2-a93b5b037ced"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/98c362a0-a10e-411b-91b6-d612105958a2"
width="300" height="600"> |
kubaflo pushed a commit that referenced this pull request Jul 15, 2026
…resources (#36097)

<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
Path.Data and Path.RenderTransform can cause memory leaks when they use
shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event
subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding
context data may also be retained.This is reproducible across platforms.

### Description of Change

<!-- Enter description of the fix in this section -->
Added weak-event subscription handling so Path no longer holds strong
references through shared geometry/transform change events.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35860 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/5bbfab0e-1978-46f9-91e2-a93b5b037ced"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/98c362a0-a10e-411b-91b6-d612105958a2"
width="300" height="600"> |
kubaflo pushed a commit that referenced this pull request Jul 22, 2026
…resources (#36097)

<!-- Please keep the note below for people who find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
Path.Data and Path.RenderTransform can cause memory leaks when they use
shared long-lived resources (PathGeometry / ScaleTransform).
The shared resource stays alive for app lifetime, and its event
subscriptions can keep old Path controls alive after a page is popped.
Because those Path controls stay alive, related page objects and binding
context data may also be retained.This is reproducible across platforms.

### Description of Change

<!-- Enter description of the fix in this section -->
Added weak-event subscription handling so Path no longer holds strong
references through shared geometry/transform change events.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35860 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/5bbfab0e-1978-46f9-91e2-a93b5b037ced"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/98c362a0-a10e-411b-91b6-d612105958a2"
width="300" height="600"> |
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-drawing Shapes, Borders, Shadows, Graphics, BoxView, custom drawing community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Path.Data / Path.RenderTransform leaks Path visual trees when using shared app-level PathGeometry or ScaleTransform

5 participants