5

I have some problems running my app on some old Androiddevices, and I therefore downloaded a trail of Visual Studio Professionel, as it has Diagnostics Tools.

I tried doing some simple stuff in my app, and I find it is scaring, that Xamarin.Forms.BindableProperty+BindablePropertyContext takes a size (in bytes of course) of 2.196.088 in UWP, which you can see at the following screendump.

UWP Managed memory.

In the example I have justed navigated through 5 pages. On 2 of the pages there are ListViews, and one of them have been cleared 3 times, and filled with new data.

So do I have to call GC.Collect() after clearing the ListView?

Lasse Madsen
  • 592
  • 9
  • 30
  • Calling `GC.Collect()` is never recommended as it may break other stuff in your code. `Clear()` for `ListView` does NOT call `Dispose()` on your objects which means `GC` has to take time to make sure those objects are not referenced anywhere else before collecting them. If you want, you could go in a loop and `Dispose()` each item in the `ListView` which will ensure you destroy them. Take a look here. http://stackoverflow.com/questions/1969024/does-calling-clear-disposes-the-items-also – Everyone Mar 17 '17 at 07:28
  • 1
    @Everyone `GC.Collect()` never breaks any other stuff, it just makes app slow as it is CPU intensive job. – Akash Kava Mar 17 '17 at 17:35
  • @AkashKava True, sorry. It consumes the performance, wouldn't break running code, but would drastically slow it down.. like A LOT – Everyone Mar 17 '17 at 18:47

1 Answers1

1

I've had a similar issue - navigating through pages a couple of times caused an OutOfMemoryException. For me the solution was to implement custom render for page with explicit Dispose() call.

public class CustomPageRenderer : PageRenderer
{
    private NavigationPage _navigationPage;

    protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
    {
        base.OnElementChanged(e);
        _navigationPage = GetNavigationPage(Element);
        SubscribeToPopped(_navigationPage);
    }

    private void SubscribeToPopped(NavigationPage navigationPage)
    {
        if (navigationPage == null)
        {
            return;
        }

        navigationPage.Popped += OnPagePopped;
    }

    protected override void Dispose(bool disposing)
    {
        Log.Info("===========Dispose called===========");
        base.Dispose(disposing);
    }

    private void OnPagePopped(object sender, NavigationEventArgs args)
    {
        if (args.Page != Element)
        {
            return;
        }

        Dispose(true);
        _navigationPage.Popped -= OnPagePopped;
    }

    private static NavigationPage GetNavigationPage(Element element)
    {
        if (element == null)
        {
            return null;
        }

        while (true)
        {
            if (element.Parent == null || element.Parent.GetType() == typeof(NavigationPage))
            {
                return element.Parent as NavigationPage;
            }

            element = element.Parent;
        }
    }
}

You can also take a look here but you need to be careful with disposing images, it may cause some problems if their parent page is in navigation stack and you want to go back.

Community
  • 1
  • 1
maddhew
  • 54
  • 2
  • Thanks @maddhew. I have just converted 90-95% of the events to Commands, which I hope will help. The other 5-10% did I move from the constructor to OnAppearing and unassigning in OnDisappearing. And I have converted all images to 9-patches (on Android). I hope it will take some of it. – Lasse Madsen Apr 04 '17 at 05:46