New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix ToolStrip memory leak due to MouseHoverTimer and #4808 #11358
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #11358 +/- ##
===================================================
+ Coverage 74.24289% 74.27562% +0.03273%
===================================================
Files 3022 3025 +3
Lines 626297 626919 +622
Branches 46702 46750 +48
===================================================
+ Hits 464981 465648 +667
+ Misses 157921 157909 -12
+ Partials 3395 3362 -33
Flags with carried forward coverage won't be shown. Click here to find out more. |
@Olina-Zhang Could your team please test this pr to confirm the issues are resolved? |
@elachlan @kirsan31 Tested this PR, just can confirm that GH issue #4808 is fixed, I am not clear how to verify #11334, can you give some more information about how to repro it?
|
Same repro app, the key is to remove item immediately after timer.mp4 |
{ | ||
// To prevent memory leaks when item removed from main collection, | ||
// we need to remove it from _displayedItems and _overflowItems too. | ||
_displayedItems?.Remove(item); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to make _displayedItems and _overflowItems collections of weak references instead?
I wonder if we have cases when item is removed but is not disposed and will be reused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to make _displayedItems and _overflowItems collections of weak references instead?
That was the first thing I thought of. But there about 100 references, it will be too overcomplicated...
I wonder if we have cases when item is removed but is not disposed and will be reused.
Both collections insertions appears only in SetDisplayedItems
and both are cleared at start of the method:
winforms/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStrip.cs
Lines 4333 to 4337 in 0aa3a4d
protected virtual void SetDisplayedItems() | |
{ | |
DisplayedItems.Clear(); | |
OverflowItems.Clear(); | |
HasVisibleItems = false; |
So, the logic must preserve.
Also. SetDisplayedItems
are called from OnLayout
and both ToolStripItemCollection.Insert
and ToolStripItemCollection.Add
are calling OnItemAdded
-> DoLayoutIfHandleCreated
-> ... SetDisplayedItems
.
P.s. I noticed a strange difference in the ToolStripItemCollection.Insert
and ToolStripItemCollection.Add
methods:
Lines 106 to 110 in 0aa3a4d
if (_itemsCollection && _owner is not null) | |
{ | |
_owner.OnItemAddedInternal(value); | |
_owner.OnItemAdded(new ToolStripItemEventArgs(value)); | |
} |
Lines 310 to 324 in 0aa3a4d
if (_itemsCollection && _owner is not null) | |
{ | |
if (_owner.IsHandleCreated) | |
{ | |
LayoutTransaction.DoLayout(_owner, value, PropertyNames.Parent); | |
} | |
else | |
{ | |
// next time we fetch the preferred size, recalc it. | |
CommonProperties.xClearPreferredSizeCache(_owner); | |
} | |
_owner.OnItemAddedInternal(value); | |
_owner.OnItemAdded(new ToolStripItemEventArgs(value)); | |
} |
this code is not present in
ToolStripItemCollection.Add
:
if (_owner.IsHandleCreated)
{
LayoutTransaction.DoLayout(_owner, value, PropertyNames.Parent);
}
else
{
// next time we fetch the preferred size, recalc it.
CommonProperties.xClearPreferredSizeCache(_owner);
}
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we own all items in these collections?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we own all items in these collections?
No of course. More of it I doubt that we own any of them. These are menu items. But all additions of these elements are of course only ours (in SetDisplayedItems
), as I wrote above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep in mind that we are removing the ToolStripItem
from our collections here and not disposing of them. So we free up the references, but aren't responsible for the lifetime.
Fix #4808 and problem that was mentioned in #11334.
Proposed changes
Replace
ToolStripItem? _currentItem
withWeakReference<ToolStripItem?> _currentItem
inMouseHoverTimer
Implement this suggestion.
Customer Impact
No more memory leak if
ToolStripItem
will be disposed after MouseHoverTimer start.No more memory leak of chilled elements due to
DisplayedItems
andOverflowItems
collections..Regression?
Risk
Minimal.
Screenshots
ToolStripItem
below was disposed, but remain in memory:Test methodology
Microsoft Reviewers: Open in CodeFlow