Xamarin.Forms样式导致WeakReference泄漏

时间:2018-01-03 16:45:12

标签: memory-leaks xamarin.forms weak-references xamarin.forms-styles

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

使用Xamarin Profiler,我可以看到,只要我创建一个Style并将其应用于一个控件(或者实际上只是一个隐式样式),我们就会得到多个WeakReferences' Live' - 即不是垃圾收集。

请注意,我假设他们引用的对象是GC(因为对象的引用是),但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>

Page 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的值以及后续设置样式时创建的。

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

使用Profiler,我可以看到我们没有标签保持不受GC影响。它似乎是主题/行为/触发器处理中的东西。

我还没有看过GitHub上的Xamarin.Forms代码 - 这可能是我的下一步行动。

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

1 个答案:

答案 0 :(得分:1)

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

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

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

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

    base.OnDisappearing();
}

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

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