This repository has been archived by the owner on May 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes memory leak from grouped ListView with HasUnevenRows set (#12447)
fixes #6742 fixes #10820 * Fixes #6742 The Item created to measure was never removed, causing memory leak until the page is closed. * cleanup * cleanup, remove UITEST code * remove commented code * remove unused variable * Fix bad merge of project file.
- Loading branch information
Showing
4 changed files
with
205 additions
and
2 deletions.
There are no files selected for viewing
31 changes: 31 additions & 0 deletions
31
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6742.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<controls:TestContentPage xmlns:controls="clr-namespace:Xamarin.Forms.Controls" | ||
xmlns="http://xamarin.com/schemas/2014/forms" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
xmlns:d="http://xamarin.com/schemas/2014/forms/design" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" | ||
x:Class="Xamarin.Forms.Controls.Issues.Issue6742"> | ||
<StackLayout> | ||
<Button AutomationId="Issue6742Refresh" Clicked="RefreshItems" Text="Refresh" BackgroundColor="Cyan"/> | ||
|
||
<Label Text="Tap Refresh button a few times." /> | ||
<Label AutomationId="Issue6742Label" Text="{Binding DisposeString}"/> | ||
<Label AutomationId="Issue6742Mem" Text="{Binding TotalMemory}"/> | ||
|
||
<ListView | ||
HasUnevenRows="True" | ||
ItemsSource="{Binding ItemGroups}" | ||
IsGroupingEnabled="True" | ||
GroupDisplayBinding="{Binding GroupName}"> | ||
<ListView.ItemTemplate> | ||
<DataTemplate> | ||
<ViewCell> | ||
<StackLayout Margin="20"> | ||
<Label Text="{Binding Name}" /> | ||
</StackLayout> | ||
</ViewCell> | ||
</DataTemplate> | ||
</ListView.ItemTemplate> | ||
</ListView> | ||
</StackLayout> | ||
</controls:TestContentPage> |
159 changes: 159 additions & 0 deletions
159
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6742.xaml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
using System; | ||
using System.Collections.ObjectModel; | ||
using System.Runtime.CompilerServices; | ||
using System.ComponentModel; | ||
using System.Collections.Generic; | ||
using Xamarin.Forms.CustomAttributes; | ||
using Xamarin.Forms.Internals; | ||
|
||
namespace Xamarin.Forms.Controls.Issues | ||
{ | ||
[Preserve(AllMembers = true)] | ||
[Issue(IssueTracker.Github, 6742, "Memory leak in ListView with uneven rows on IOS", PlatformAffected.Default)] | ||
public partial class Issue6742 : TestContentPage | ||
{ | ||
public Issue6742() | ||
{ | ||
#if APP | ||
InitializeComponent(); | ||
#endif | ||
BindingContext = viewModel = new ViewModelIssue6742(); | ||
|
||
} | ||
protected override void Init() | ||
{ | ||
|
||
} | ||
ViewModelIssue6742 viewModel; | ||
IList<WeakReference<ModelIssue6742>> _weakList = new List<WeakReference<ModelIssue6742>>(); | ||
private void RefreshItems(object sender, EventArgs e) | ||
{ | ||
foreach (var item in this.viewModel.ItemGroups) | ||
{ | ||
item.Clear(); | ||
} | ||
viewModel.ItemGroups.Clear(); | ||
|
||
GC.Collect(); | ||
GC.WaitForPendingFinalizers(); | ||
GC.Collect(); | ||
|
||
CleanWeakList(_weakList); | ||
viewModel.DisposeString = $"{_weakList.Count} object(s) alive"; | ||
|
||
string report = $"MEMORY:{GC.GetTotalMemory(true)}"; | ||
viewModel.TotalMemory = report; | ||
|
||
var g1 = new ModelIssue6742Group("Group 1") | ||
{ | ||
new ModelIssue6742("first", viewModel), | ||
new ModelIssue6742("second", viewModel), | ||
}; | ||
|
||
_weakList.Add(new WeakReference<ModelIssue6742>(g1[0])); | ||
_weakList.Add(new WeakReference<ModelIssue6742>(g1[1])); | ||
|
||
viewModel.ItemGroups.Add(g1); | ||
|
||
var g2 = new ModelIssue6742Group("Group 2") | ||
{ | ||
new ModelIssue6742("third", viewModel), | ||
new ModelIssue6742("fourth", viewModel), | ||
}; | ||
|
||
_weakList.Add(new WeakReference<ModelIssue6742>(g2[0])); | ||
_weakList.Add(new WeakReference<ModelIssue6742>(g2[1])); | ||
|
||
viewModel.ItemGroups.Add(g2); | ||
|
||
var g3 = new ModelIssue6742Group("Group 3") | ||
{ | ||
new ModelIssue6742("fifth", viewModel), | ||
new ModelIssue6742("sixth", viewModel), | ||
new ModelIssue6742("seventh", viewModel), | ||
}; | ||
|
||
_weakList.Add(new WeakReference<ModelIssue6742>(g3[0])); | ||
_weakList.Add(new WeakReference<ModelIssue6742>(g3[1])); | ||
_weakList.Add(new WeakReference<ModelIssue6742>(g3[2])); | ||
|
||
viewModel.ItemGroups.Add(g3); | ||
} | ||
|
||
private void CleanWeakList(IList<WeakReference<ModelIssue6742>> weakList) | ||
{ | ||
ModelIssue6742 item; | ||
for (int i = weakList.Count-1; i >= 0; i--) | ||
{ | ||
if (!weakList[i].TryGetTarget(out item)) | ||
{ | ||
weakList.RemoveAt(i); | ||
} | ||
} | ||
} | ||
} | ||
|
||
[Preserve(AllMembers = true)] | ||
public class ViewModelIssue6742 : INotifyPropertyChanged | ||
{ | ||
public ObservableCollection<ModelIssue6742Group> ItemGroups { get; set; } = new ObservableCollection<ModelIssue6742Group>(); | ||
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; | ||
|
||
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null) | ||
{ | ||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); | ||
} | ||
|
||
|
||
string _DisposeString; | ||
public string DisposeString | ||
{ | ||
get { return _DisposeString; } | ||
set | ||
{ | ||
_DisposeString = value; | ||
NotifyPropertyChanged(); | ||
} | ||
} | ||
|
||
string _totalMemory; | ||
public string TotalMemory | ||
{ | ||
get => _totalMemory; | ||
set | ||
{ | ||
_totalMemory = value; | ||
NotifyPropertyChanged(); | ||
} | ||
} | ||
|
||
public ViewModelIssue6742() | ||
{ | ||
|
||
} | ||
} | ||
|
||
[Preserve(AllMembers = true)] | ||
public class ModelIssue6742Group : ObservableCollection<ModelIssue6742> | ||
{ | ||
public ModelIssue6742Group(string name) | ||
{ | ||
GroupName = name; | ||
} | ||
public string GroupName { get; set; } | ||
|
||
} | ||
|
||
[Preserve(AllMembers = true)] | ||
public class ModelIssue6742 | ||
{ | ||
ViewModelIssue6742 _model; | ||
|
||
public ModelIssue6742(string name, ViewModelIssue6742 model) | ||
{ | ||
_model = model; | ||
Name = name; | ||
} | ||
public string Name { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters