内存泄漏 – 导致WeakReference泄漏的Xamarin.Forms样式

我花了很多时间在
Android上的Xamarin.Forms应用程序中追踪内存泄漏.在经历了很多盲目的小巷和虚假的曙光之后,我想我可能遇到了导致这个问题的事情.

使用Xamarin Profiler,我可以看到,只要我创建一个Style并将其应用于一个控件(或者实际上只是一个隐式样式),我们就会让多个WeakReferences保持“实时” – 即不是垃圾收集.

请注意,我假设它们引用的对象已经过GC’d(因为对对象的引用很弱),但WeakReferences本身仍然存在.

当然,WeakReferences当然很小 – 但是当你在页面推送/弹出的每次迭代中创建了数百个时,那么内存会增加并且我们会有很大的泄漏.

这是详细信息.
使用Xamarin.Forms 2.3.4.270(我们还没有升级,因为我们想要保持已知问题!)
在Android上运行 – 物理设备.

App.xaml中:

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:ProfiledFormsApp2;assembly=ProfiledFormsApp2" 
     x:Class="ProfiledFormsApp2.App">
    <Application.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="FontSize" Value="Large" />
                <Setter Property="TextColor" Value="Blue" />
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

页面XAML:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage Title="Plain Page" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ProfiledFormsApp2.PlainPage">
    <ContentPage.Content>
        <StackLayout>
            <StackLayout Orientation="Horizontal">
                <Label Text="Core Navigation"/>
                <Label Text="Number of items:" />
                <Label Text="{Binding ItemsCount}" />
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

当我导航到上面的页面并返回3次时,我们创建了以下WeakReference(及相关)类 – 下面的截图来自Profiler快照.

请注意,我们有55个WeakReferences.深入研究这些节目:

有趣的是,这些WeakReferences似乎是作为行为和触发器附加的一部分创建的.查看顶部调用树给出:

因此,看起来WeakReference是作为设置BindableObject的值和Style的后续设置的一部分创建的.

并且看起来WeakReference仍然在内存中并被某些东西引用 – 行为集合?

使用Profiler,我可以看到我们没有标签保持未GC.它似乎是主题/行为/触发器处理中的一些东西.

我还没有看过GitHub上的Xamarin.Forms代码 – 这可能是我的下一个动作.

有没有人观察到这个或得到解决方案?

最佳答案 我不确定控件的隐式样式,但是对于显式样式,您可以在页面超出范围时删除它们或消失.

例如,我们将一个显式样式应用于按钮

<Button x:Name="btnSave" Style="{StaticResource SaveButtonStyle}" Content="Save"/>

protected override void OnDisappearing()
{
    btnSave.Style = null;

    base.OnDisappearing();
}

同样可以使用触发器和行为完成(您可以清除它们).

我认为对于隐式样式,框架代码中只有一些内容.我们无法确定默认控件的默认控件如何附加控件.

点赞