Skip to content

[TrimmableTypeMap] fix JavaPeerableProxy activation gref leak - #11116

Closed
simonrozsival wants to merge 8 commits into
mainfrom
dev/simonrozsival/11101-trimmable-typemap-followup
Closed

[TrimmableTypeMap] fix JavaPeerableProxy activation gref leak#11116
simonrozsival wants to merge 8 commits into
mainfrom
dev/simonrozsival/11101-trimmable-typemap-followup

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Apr 15, 2026

Copy link
Copy Markdown
Member

Follow-up to #11112.

This PR keeps the trimmable typemap side of the remaining activation leak fix, scoped to generated proxy activation:

  • add JavaPeerProxy.CreateActivatedPeer(Type, IntPtr) as the shared helper for inherited Java activation paths
  • update inherited-constructor proxy generation to use the shared helper instead of repeating the activation sequence at each call site
  • keep the trimming contract explicit by passing an annotated Type instead of relying on a trim suppression
  • add and update TypeMapAssemblyGeneratorTests coverage

CopilotAI review requested due to automatic review settings April 15, 2026 09:00
@simonrozsival
simonrozsivalforce-pushed the dev/simonrozsival/11101-trimmable-typemap-followup branch from 007428d to ab6d8daCompareApril 15, 2026 09:02

CopilotAI 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.

Pull request overview

This PR addresses a remaining JNI global reference leak in the NativeAOT / trimmable typemap activation path by ensuring activated peers are constructed (and marked) before invoking inherited activation constructors, and adds regression coverage for both runtime and generator behavior.

Changes:

  • Add JavaPeerProxy.ConstructActivatedPeer() helper for typemap-generated proxy activation.
  • Update typemap proxy IL emission to pre-construct activated peers before calling inherited activation constructors/UCO constructors.
  • Add regression tests: device-side gref leak test during inflation, and generator-side metadata coverage for the new helper reference.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Android.Widget/CustomWidgetTests.csAdds a device regression test to detect global-ref growth across repeated inflations.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csExtends generator tests to ensure the new helper is referenced in generated assemblies.
src/Mono.Android/Java.Interop/TypeManager.csUpdates Activate() to construct the peer via ValueManager.ConstructPeer() using the shared uninitialized-object helper.
src/Mono.Android/Java.Interop/JavaPeerProxy.csIntroduces ConstructActivatedPeer() to centralize “pre-construct activated peer” logic for proxies.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits calls to ConstructActivatedPeer() for inherited activation ctor/UCO paths to prevent duplicate gref creation.

@simonrozsivalsimonrozsival changed the title [TrimmableTypeMap] fix NativeAOT inherited activation leak[TrimmableTypeMap] fix JavaPeerableProxy activation leakApr 15, 2026
@simonrozsivalsimonrozsival changed the title [TrimmableTypeMap] fix JavaPeerableProxy activation leak[TrimmableTypeMap] fix JavaPeerableProxy activation gref leakApr 15, 2026
@simonrozsivalsimonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels Apr 15, 2026
@simonrozsival
simonrozsival changed the base branch from dev/peppers/fix-activate-gref-leak to mainApril 15, 2026 12:32
jonathanpeppersand others added 5 commits April 15, 2026 14:34
Fixes: #11101Fixes: #10989
Context: 5c23bcda8 (PR #9640)
The Java.Interop Unification (5c23bcd) changed `Object` to extend
`JavaObject`, introducing an additional `ConstructPeer` call in the
constructor chain. `TypeManager.Activate` was updated to use
`SetPeerReference` but never set the `Activatable` state flag.
Without it, each `ConstructPeer` call in the constructor chain
(`JavaObject()` and `Object.SetHandle()`) creates a new JNI global
ref, overwriting the previous one without deleting it — leaking 3
global refs per `LayoutInflater.Inflate` call.
Before the fix, the new test fails with:
Global reference leak detected: 30 extra global refs after
inflating/GC'ing 10 custom views. Before=207, After=237
This went unnoticed because the `Activate` path is only triggered
when Java creates .NET objects (not the other way around). The two
main scenarios are Activity recreation and custom C# views in Android
XML layouts. Most developers use .NET MAUI, which has a single
Activity and does not use custom C# views in Android layout XML files,
so neither scenario was commonly hit.
Changes:
- Promote `GetUninitializedObject` from a local function in
`CreateProxy` to a shared static method. It sets
`Activatable | Replaceable`, which tells `ConstructPeer` to
return early and not create duplicate global refs.
- Have `Activate` call `GetUninitializedObject` then
`ConstructPeer` to create one global ref while `jobject` is
still a valid JNI local ref. The `Activatable` flag then prevents
duplicates during the constructor chain.
- Add regression test that inflates custom views and asserts JNI
global reference count does not grow.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival
simonrozsivalforce-pushed the dev/simonrozsival/11101-trimmable-typemap-followup branch from 125e014 to 19c0bc7CompareApril 15, 2026 12:35
simonrozsivaland others added 3 commits April 15, 2026 14:39
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thistrimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@simonrozsival@jonathanpeppers