Утечка 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;
    }
}
Другие вопросы по тегам