Утечка Xamarin.Forms на Android делает простой push/pop страницы?
Я исследую утечку памяти (или утечки), которая, кажется, является основной для нашего приложения Forms.
Мы используем FreshMvvm, который ранее имел довольно серьезную утечку из-за того, что Pages/PageModels не собирали мусор. Майкл Ридланд (автор FreshMvvm) исправил это, и это здорово.
Тем не менее, мы все еще видим, что число, возвращаемое GC.GetTotalMemory(), постоянно увеличивается. Это уменьшается, но общая тенденция - вверх.
Я удалил вещи обратно, так что у меня есть просто страница, которая нажимает на другую страницу, и мы можем затем вернуться к первой.
Делая это, я вижу, что GC.GetTotalMemory() обычно увеличивается на 2K - 4K каждый цикл. Это после принудительного вызова GC.Collect();
Мы запускаем Xamarin.Forms 2.3.4.270 - я знаю, что он довольно старый, но мы действительно не хотим обновляться, поскольку не хотим вводить ошибки "новых форм"! Тем не менее, я попытался экспериментально обновить до 2.5.0.121934, и я вижу то же поведение (а также аспекты приложения перестают работать с этой версией).
Кроме использования Profiler, есть ли какие-либо методы расследования, которые я могу использовать, чтобы найти преступника?
Мой следующий шаг будет раздеться все больше и больше!
1 ответ
Я сталкивался с подобной проблемой в прошлом с утечками памяти в Xamarin.Forms и чтобы выяснить, какие виды / страницы были виновником этого класса:
public static class Refs
{
private static readonly List<WeakReference> _refs = new List<WeakReference>();
public static readonly BindableProperty IsWatchedProperty = BindableProperty.CreateAttached("IsWatched", typeof(bool), typeof(Refs), false, propertyChanged: OnIsWatchedChanged);
public static bool GetIsWatched(BindableObject obj)
{
return (bool)obj.GetValue(IsWatchedProperty);
}
public static void SetIsWatched(BindableObject obj, bool value)
{
obj.SetValue(IsWatchedProperty, value);
}
private static void OnIsWatchedChanged(BindableObject bindable, object oldValue, object newValue)
{
AddRef(bindable);
}
public async static void AddRef(object p)
{
GC.Collect();
await Task.Delay(100);
GC.Collect();
_refs.Add(new WeakReference(p));
foreach (var @ref in _refs)
{
if (@ref.IsAlive)
{
var obj = @ref.Target;
Debug.WriteLine("IsAlive: " + obj.GetType().Name);
}
else
{
Debug.WriteLine("IsAlive: False");
}
}
Debug.WriteLine("---------------");
}
}
Затем, чтобы использовать его, вы можете использовать свойство IsWatched на своих страницах xaml или в коде, который вы можете просто сделать Refs.AddRef(this);
после InitializeComponent();
и просто переходите на страницу и с нее несколько раз. Если это gc'ed, консоль должна напечатать IsAlive: False, если нет, она выведет тип.
Чаще всего утечки, которые мы имели, были устранены путем очистки BindingContext и / или установки некоторых элементов в null при выходе из страницы.
protected override void OnParentSet()
{
base.OnParentSet();
if (Parent == null)
{
BindingContext = null;
}
}