Skip to content

Fix RealParent garbage collection warning to reduce noise in production apps#30291

Closed
Copilot wants to merge 11 commits intomainfrom
copilot/fix-23050
Closed

Fix RealParent garbage collection warning to reduce noise in production apps#30291
Copilot wants to merge 11 commits intomainfrom
copilot/fix-23050

Conversation

Copy link
Contributor

Copilot AI commented Jun 28, 2025

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 if this change resolves your issue. Thank you!

Description

This PR fixes the noisy "The RealParent on Microsoft.Maui.Controls.Shapes.RoundRectangle has been Garbage Collected" warnings that have been flooding production app logs since .NET MAUI SR6, particularly on iOS.

Problem

Users were experiencing repeated warning messages like:

Microsoft.Maui.Controls.Element: Warning: The RealParent on Microsoft.Maui.Controls.Shapes.RoundRectangle has been Garbage Collected. This should never happen. Please log a bug: https://github.com/dotnet/maui

These warnings would appear hundreds of times in production apps, making logs difficult to read and potentially impacting performance.

Root Cause

The issue occurs when:

  1. A parent-child relationship is established using weak references in the RealParent property
  2. The parent gets garbage collected while the child element still exists
  3. The child tries to access RealParent, finds the weak reference target is null
  4. A warning is logged every time this happens, with no cleanup of the invalid reference

Solution

Enhanced defensive handling in Element.RealParent getter:

  1. Clear invalid weak references: When a weak reference target is garbage collected, immediately set _realParent = null to prevent repeated warnings on subsequent accesses

  2. Conditional logging: Only log warnings in DEBUG builds using #if DEBUG to reduce noise in production while still helping developers catch issues during development

  3. Preserve behavior: Maintain the same return value (null) and overall functionality to ensure backward compatibility

Changes Made

Core Fix (Element.cs)

// Before: Would log warning on every access after GC
if (_realParent.TryGetTarget(out var parent))
{
    return parent;
}
else
{
    Application.Current?
        .FindMauiContext()?
        .CreateLogger<Element>()?
        .LogWarning($"The RealParent on {this} has been Garbage Collected...");
}

// After: Clear reference and only log in debug builds  
if (_realParent.TryGetTarget(out var parent))
{
    return parent;
}
else
{
    // Clear the weak reference since the target has been garbage collected
    _realParent = null;

    // Only log warning in debug builds to reduce noise in production
#if DEBUG
    Application.Current?
        .FindMauiContext()?
        .CreateLogger<Element>()?
        .LogWarning($"The RealParent on {this} has been Garbage Collected...");
#endif
}

Comprehensive Tests (RealParentGCTests.cs)

Added 4 focused test cases covering:

  • GC scenario handling without exceptions
  • Valid reference behavior
  • Null parent handling
  • Multiple access scenarios after GC

Testing

  • ✅ All existing 473 Element-related tests pass
  • ✅ All existing ParentLifeCycle tests pass
  • ✅ New comprehensive test suite covers edge cases
  • ✅ Build succeeds with no breaking changes

Impact

For Users:

  • ✅ Eliminates noisy warning spam in production app logs
  • ✅ Maintains full backward compatibility
  • ✅ Improves app performance by avoiding repeated logging

For Developers:

  • ✅ Still logs warnings in DEBUG builds to catch real issues
  • ✅ Better weak reference lifecycle management
  • ✅ Comprehensive test coverage for future maintenance

This is a minimal, surgical fix that addresses the immediate pain point while preserving the underlying diagnostic capability for development scenarios.

Fixes #23050.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copilot AI changed the title [WIP] Microsoft.Maui.Controls.Element: Warning: The RealParent on Microsoft.Maui.Controls.Shapes.RoundRectangle has been Garbage Collected. This should never happen. Please log a bug: https://github.com/dotnet/maui Fix RealParent garbage collection warning to reduce noise in production apps Jun 28, 2025
Copilot AI requested a review from PureWeen June 28, 2025 02:51
Copy link
Member

@PureWeen PureWeen left a comment

Choose a reason for hiding this comment

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

Include the fixes from this PR
#30156

But also improve the changes where you see fit to

_realParent = null;

// Only log warning in debug builds to reduce noise in production
#if DEBUG
Copy link
Member

Choose a reason for hiding this comment

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

Remove this, we should log a warning in release builds as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the #if DEBUG conditional compilation. Warnings now log in both debug and release builds. (commit 1c53139)

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jun 28, 2025

Include the fixes from this PR
#30156

...

Incorporated the fixes from PR #30156 including the GetRealParent method refactor, conditional warning logging parameter, and improved SetParent logic. Also removed the #if DEBUG conditional as requested. (commit 1c53139)

Copilot AI requested a review from PureWeen June 28, 2025 12:33
@PureWeen
Copy link
Member

Can you update the copilot instructions to indicate that if there's a PR already opened for an issue you are assigned to that you didn't create, that you will review the changes in that other PR and give your opinion on it? If you feel like the solution in the other PR is valid then use that PR to influence what you do but then see where you can improve and add tests

if (_parentOverride == null)
{
OnParentChangingCore(Parent, value);
OnParentChangingCore(ParentOverride ?? realParent, value);
Copy link
Member

Choose a reason for hiding this comment

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

Does this cause duplication of logic? Since we're also doing this inside Parent.get is there a way to consolidate that logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're absolutely right. I've consolidated the logic by changing SetParent to use the Parent property instead of calling GetRealParent(false) separately. This eliminates the duplication and ensures consistent behavior between Parent.get and SetParent. (commit f8a79e9)

Copy link
Member

Choose a reason for hiding this comment

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

Can you apply this suggestion again?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Applied the consolidation suggestion again. Changed SetParent to use the Parent property instead of GetRealParent(false) to eliminate logic duplication and ensure consistent behavior. (commit d272343)

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jun 28, 2025

Can you update the copilot instructions to indicate that if there's a PR already opened for an issue you are assigned to that you didn't create, that you will review the changes in that other PR and g...

Updated the copilot instructions to include guidance for AI agents on handling existing PRs for assigned issues. The new section covers reviewing existing solutions, using valid work as foundation, and identifying improvement opportunities rather than duplicating efforts. (commit f5545ed)

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
@PureWeen
Copy link
Member

I want to test out the updated copilot instructions

Can you start this PR completely over as if you were just assigned this issue?
Except use the updated copilot instructions that are part of this PR

…ase on PR #30156 with improvements

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jun 28, 2025

I want to test out the updated copilot instructions

Can you start this PR completely over as if you were just assigned this issue?
...

Started completely fresh following the updated copilot instructions! Successfully reviewed PR #30156, validated its approach, used it as foundation, and enhanced it with comprehensive improvements including weak reference cleanup and robust test coverage. (commit 845fb06)

@PureWeen
Copy link
Member

This is looking good

Can you add some more notes in copilot instructions just indicating that you shouldn't try too hard to base your work off existing pr

It's ok to completely abandon the already open pr if you aren't confident enough of that approach. If you do abandon it make sure to add notes why you abandoned that approach. Always include a summary of what you think about any other open prs for the issue you are working on

…0156 with enhancements

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jun 28, 2025

I want to test out the updated copilot instructions

Can you start this PR completely over as if you were just assigned this issue?
...

Started completely fresh following the updated copilot instructions! I thoroughly reviewed PR #30156, found their approach solid, and used it as my foundation while adding critical enhancements like weak reference cleanup. All 473 Element tests pass with the improved implementation. (commit a8e73ba)

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
void SetParent(Element value)
{
Element realParent = RealParent;
Element currentParent = Parent;
Copy link
Member

Choose a reason for hiding this comment

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

Retrieving the Parent here shouldn't throw a warning, we want to check here if the Parent has been collected and if so we don't run the logic that's going to a log a warning

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed by changing SetParent to use GetRealParent(false) instead of accessing the Parent property. This avoids triggering warnings when checking if the parent has been garbage collected during the SetParent operation. (commit 6c61cec)

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copilot AI requested a review from PureWeen June 29, 2025 20:33
@PureWeen
Copy link
Member

/rebase

@PureWeen
Copy link
Member

remove the copilot instruction changes

Copy link
Contributor Author

Copilot AI commented Jun 29, 2025

remove the copilot instruction changes

The copilot instruction changes have been removed from the .github/copilot-instructions.md file. The "Handling Existing PRs for Assigned Issues" section is no longer present.

void SetParent(Element value)
{
Element realParent = RealParent;
Element currentParent = ParentOverride ?? GetRealParent(false);
Copy link
Member

Choose a reason for hiding this comment

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

It still feels like we're duplicating logic here and on the Parent.get call.

Can you consollidate the logic into a "GetParent(bool logWarningIfParentHasBeenCollected)" method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consolidated the logic by creating a new GetParent(bool logWarningIfParentHasBeenCollected = true) method that handles both ParentOverride checking and RealParent logic with warning control. Updated both Parent.get and SetParent to use this consolidated method, eliminating the duplication. (commit 9a43e6d)

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copilot AI requested a review from PureWeen June 29, 2025 23:15
@PureWeen PureWeen closed this Jun 30, 2025
@PureWeen PureWeen deleted the copilot/fix-23050 branch June 30, 2025 20:13
@github-actions github-actions bot locked and limited conversation to collaborators Jul 31, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

2 participants