Repository navigation
[release/11.0.1xx] [Java.Interop] Release native peer control blocks on finalization - #13294
Conversation
Preserve the value-manager callback ordering and release cleared JavaObject and JavaException control blocks after Dispose(false), including exceptional callbacks. Keep references reconstructed by derived callbacks alive. Cover normal, invalid, partial-construction, resurrection, and explicit-disposal lifetimes separately from JNI reference counts. Refs #13010 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Share the finalization validity guard between JavaObject and JavaException without changing callback or reference-tracking context ordering. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep native allocation and callback checks in the ordinary shared-VM suite. Move exact GREF-count assertions to the dedicated JniReferenceLeak selection and warm peer caches after collection, so unrelated runtime activity does not mask the lifetime regression checks. Refs #13010 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove the retired JavaVMFixture inheritance and host-only registered-peer cleanup. Current main removed the reflection-backed JVM harness; the shared fixture now follows its no-base Android convention and exercises the actual bridge finalizer path. Refs #13010 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Exercise successful and throwing finalization callbacks for both peer types after valid reconstruction. Verify retained JNI identity and registration, then explicit disposal releases the native block and removes registration. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Initialize the JVM for focused fixture runs and keep host finalizer test peers out of the strong-reference registry. Preserve Android registration behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@dalexsoto review |
|
Verified this PR with the actual Source and test settings
The unfixed revision is the original The comparison used the same owned Android 10/API 29 x86_64 emulator, CoreCLR/.NET 11.0.0, Android workload pack version 37.2.1, and JDK 17. The source SDK/framework configuration was Debug; the sample was Release, with trimming, ReadyToRun, the interpreter, and marshal methods disabled. The private SDK reports This is the downloaded SDK's restriction, not a conclusion that the release-branch source contains no Mono runtime code. Both measured variants use CoreCLR. Sample configuration changes were the SDK pin MeasurementsFirst completed the original four cases: finalization and explicit Then repeated all four cases with the sample's supported All changes below are in bytes. Batch 0 is after warm-up; batches 50-100 cover 250,000 new wrappers.
In the last 250,000 allocations, unfixed finalization added 16.979 native bytes per wrapper, while fixed finalization changed by -0.078 bytes per wrapper. These are endpoint changes divided by allocation count, not median per-batch changes. Managed and Java live memory stayed unchanged in both finalization runs during that interval. The unfixed finalization increase exceeded its disposal control by 4,132,656 bytes in that window, or about 16.531 bytes per wrapper. That is consistent with the .NET 11 control-block payload's 16-byte size on x64, rather than the 32-byte reference measurements from the .NET 10 sample. The size comparison is supporting evidence, not an exact count of leaked blocks. Both disposal controls and fixed finalization lack the continuing increase seen with unfixed finalization. Remaining positive/negative changes include background allocation and allocator/cache cleanup; a negative delta is not a negative control-block count or proof of a permanent memory plateau. Framework identity checks and limitsDecoded the managed framework payloads from each actual signed APK. The sample/helper DLLs, Stock mode leaves the optional probe counters at zero. These results measure aggregate native allocation growth after the sample's finalizer drains, with live-heap observations and disposal controls; they are not direct per-block allocation/free or finalization-event counts. This verifies removal of the sample's continuing native growth on this .NET 11 CoreCLR/x86_64 configuration. Mono and ARM64 hardware were not verified, and this does not establish that all native memory growth in a larger app is fixed. Exact commands, build logs/binlogs, signed APKs, DLL hashes, and all eight measurement captures were retained locally. |
|
@dalexsoto stamp |
dalexsoto
left a comment
There was a problem hiding this comment.
Stamping as requested by @jonathanpeppers; no code review performed.
|
Checked the failures in Azure build 1652683, which tested PR head
For the device-parameter failure, inspected the attached The test-results page also retains an earlier MAUI CoreCLR/ARM64 Full R2R failure. Its Helix console shows APK installation failed with The Java.Interop host suite now passes on both Windows and macOS: 748 passed, 5 skipped on each. The four |
Backport only the unregistered-disposal correction from c663cd1 (#12772), without its peer-identity and activation changes. DisposePeerUnlessReferenced() bypasses Disposed()/Dispose(true) when it calls the private reference-deletion helper. JavaObject and JavaException then retain their native control blocks after the JNI reference is cleared and finalization is suppressed. Use the public DisposePeer(value) path so managed disposal precedes normal cleanup. Add a distinct JavaVMFixture-based fixture for this branch's host JVM and Android inclusion paths. Cover valid-reference callback entry, native-block release, registered no-ops, alias winners, throwing callbacks and retry, repeated disposal, exact Rect disposal, and separate warmed global-reference deletion checks. The source-built Release SDK passes 12 host-JVM tests and 9 ordinary plus 7 dedicated GREF tests on each of CoreCLR and NativeAOT. The original helper produces exactly 6 host and 7 device failures; restore the production correction before repeating positive validation. Complement the finalization backport in #13294 without duplicating its implementation or JavaPeerControlBlockTests fixture. Refs #13290, #13292, #13294 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 97270e0d-9fba-4a8b-8a04-9b7c25e1cd21
Backport of #13016 to release/11.0.1xx
/cc @jonathanpeppers @simonrozsival