Ist dies ein Speicherverlust in Xamarin Forms?

Ich bin auf ein Problem gestoßen, bei dem es den Anschein hat, dass Seitenobjekte nicht mehr mit Garbage Collected erfasst werden, nachdem sie entfernt wurden. Ich habe ein sehr einfaches Beispiel dafür zusammengestellt, das das Problem bei Verwendung einer NavigationPage und der PushAsync-Methode veranschaulicht. Auf der Seite wird die Anzahl der aktiven Seiten anhand einer Liste mit schwachen Referenzen angezeigt:

public class AppNavigationPage
{
    private static List<WeakReference> pageRefs = new List<WeakReference>();

    public static Page GetMainPage()
    {
        return new NavigationPage(CreateWeakReferencedPage());
    }

    private static Page CreateWeakReferencedPage()
    {
        GC.Collect();
        var result = CreatePage();
        pageRefs.Add(new WeakReference(result));

        // Add a second unreferenced page to prove that the problem only exists
        // when pages are actually navigated to/from
        pageRefs.Add(new WeakReference(CreatePage()));
        GC.Collect();
        return result;
    }

    private static Page CreatePage()
    {
        var page = new ContentPage();
        var contents = new StackLayout();

        contents.Children.Add(
            new Button
            {
                Text = "Next Page",
                Command = new Command(() => page.Navigation.PushAsync(CreateWeakReferencedPage()))
            });
        contents.Children.Add(
            new Label
            {
                Text = string.Format(
                    "References alive at time of creation: {0}",
                    pageRefs.Count(p => p.IsAlive)),
                HorizontalOptions = LayoutOptions.CenterAndExpand
            });

        page.Content = contents;
        return page;
    }
}

Wenn Sie auf die Schaltfläche Nächste Seite klicken, wird eine neue Seite mit einer Bezeichnung mit festem Wert erstellt, die die Anzahl der aktiven Seitenverweise zum Zeitpunkt der Erstellung dieser Seite angibt. Jedes Mal, wenn Sie auf die Schaltfläche klicken, wird diese Zahl offensichtlich um 1 erhöht. Wenn Sie auf der Navigationsseite auf "Zurück" klicken, sollte die Ansicht vom Stapel entfernt und weggeworfen werden (so dass sie mit GCs versehen werden kann). . Wenn ich diesen Testcode ausführe, bedeutet dies jedoch, dass diese Ansicht nach dem Zurückkehren im Speicher erhalten bleibt. Dies kann demonstriert werden, indem Sie einige Male auf Nächste Seite klicken, bis der Referenzzähler auf 3 steht. Wenn Sie dann auf Zurück und dann auf Nächste Seite klicken, sollte der Referenzzähler meines Erachtens immer noch 3 betragen (was darauf hinweist, dass die alte Seite vor der neuen gcd wurde) man wurde erstellt) aber der neue Referenzzähler ist jetzt 4.

Dies scheint ein ziemlich schwerwiegender Fehler in der X-Forms-Navigationsimplementierung für iOS zu sein (ich habe dies nicht für andere Plattformen getestet). Ich vermute, es hängt irgendwie mit dem hier beschriebenen Problem des starken Referenzzyklus zusammen:http://developer.xamarin.com/guides/cross-platform/application_fundamentals/memory_perf_best_practices/

Hat dies jemand anderem begegnet und / oder eine Lösung / Problemumgehung dafür gefunden? Würde sonst noch jemand zustimmen, dass dies ein Fehler ist?

Außerdem habe ich ein zweites Beispiel erstellt, das keine NavigationPage enthält (daher muss stattdessen PushModalAsync verwendet werden), und festgestellt, dass ich das gleiche Problem hatte, sodass dieses Problem nicht nur für die NavigationPage-Navigation gilt. Als Referenz ist der Code für diesen (sehr ähnlichen) Test hier:

public class AppModal
{
    private static List<WeakReference> pageRefs = new List<WeakReference>();

    public static Page GetMainPage()
    {
        return CreateWeakReferencedPage();
    }

    private static Page CreateWeakReferencedPage()
    {
        GC.Collect();
        var result = CreatePage();
        pageRefs.Add(new WeakReference(result));

        // Add a second unreferenced page to prove that the problem only exists
        // when pages are actually navigated to/from
        pageRefs.Add(new WeakReference(CreatePage()));
        GC.Collect();
        return result;
    }

    private static Page CreatePage()
    {
        var page = new ContentPage();
        var contents = new StackLayout();

        contents.Children.Add(
            new Button
            {
                Text = "Next Page",
                Command = new Command(() => page.Navigation.PushModalAsync(CreateWeakReferencedPage()))
            });
        contents.Children.Add(
            new Button
            {
                Text = "Close",
                Command = new Command(() => page.Navigation.PopModalAsync())
            });
        contents.Children.Add(
            new Label
            {
                Text = string.Format(
                    "References alive at time of creation: {0}",
                    pageRefs.Count(p => p.IsAlive)),
                HorizontalOptions = LayoutOptions.CenterAndExpand
            });

        page.Content = contents;
        return page;
    }
}

Antworten auf die Frage(1)

Ihre Antwort auf die Frage