GTK - Why are multiple renderer instances being created?

knierknier Member

I'm using Xamarin.Forms with a GTK platform and I'm seeing situations where multiple renderer instances are being created and not destroyed. I was able to replicate the issue with a small code sample to post here. Every time the button on this page is clicked, it makes 1 more label renderer instance than the last time it was clicked (e.g. on the 100th click it makes 100 new label renderer instances, etc). A large part of my application is built around adding and removing Views. Situations like this are creating memory leaks and adding to my page navigation time. Is there anything I can do to avoid this or have it reuse renderers?

ExamplePage.xaml

    <ContentPage.Content>
        <StackLayout x:Name="PageStack">
            <Button Clicked="Button_Clicked"/>
        </StackLayout>
    </ContentPage.Content>

ExamplePage.xaml.cs

namespace Example
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ExamplePage : ContentPage
    {
        StackLayout stack;
        Label label;

        public ExamplePage()
        {
            InitializeComponent();

            stack = new StackLayout();
            label = new Label();
            stack.Children.Add(label);
            PageStack.Children.Add(stack);
        }

        private void Button_Clicked(object sender, EventArgs e)
        {
            PageStack.Children.Remove(stack);
            stack.Children.Remove(label);
            stack.Children.Add(label);
            PageStack.Children.Add(stack);
        }
    }
}

Answers

  • JohnHardmanJohnHardman mod GBUniversity mod
    edited August 13

    @knier

    I don't use GTK, but if implementation on GTK is similar to other platforms, I wonder if you may be hitting this - https://github.com/xamarin/Xamarin.Forms/issues/6305 (which was created as a result of https://github.com/xamarin/Xamarin.Forms/issues/6331 ).

    Undocumented, and incredibly confusing as a result until you realise it is being done, is that some (most) renderers call GC.SuppressFinalize . As a result, the renderers' finalizers are not called. If you have created custom renderers and are checking for the finalizers to be called to see if there are memory leaks, you will get an unexpected result as the cleanup is being done in the dispose handler, with the finalizer not being called. Cleanup is being done (hopefully - see caveat below), it's just the finalizers are not being called.

    Caveat: Note that the last time I checked (Xamarin.Forms 3.x, I haven't checked on 4.x yet), there were still renderers that were not cleaning up correctly, but those were a small minority.

  • knierknier Member

    In the case that I posted, the Dispose method doesn't get hit while you're still on the page. I observed this for custom renderers and the default renderers. Also, disposing is only half the problem. I don't think Xamarin should be creating multiple renderers for one instance of a View.

Sign In or Register to comment.