Xamarin.Forms样式导致WeakReference泄漏

4

我一直在花费很多时间追踪我们的Xamarin.Forms应用程序在Android上的内存泄漏问题。经过许多盲目的尝试和失败的尝试后,我认为我可能找到了导致问题的原因。

使用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值及随后设置样式的一部分而创建的。
同时,它似乎仍然在内存中,并且被某个东西引用 - 行为集合?
使用Profiler,我可以看到我们没有留下未GC'd的标签。似乎是主题/行为/触发器处理中的某些东西。
我还没有查看GitHub上的Xamarin.Forms代码 - 那可能是我的下一步行动。
有人观察到此问题或有解决方案吗?

你有没有找到这个问题的解决方案?我想你使用了FreshMVVM,这也可能是原因。 - Emil
1个回答

1
我不确定控件的隐式样式,但对于显式样式,您可以在页面超出范围或消失时将其移除。
例如,我们对按钮应用了显式样式。
<Button x:Name="btnSave" Style="{StaticResource SaveButtonStyle}" Content="Save"/>

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

    base.OnDisappearing();
}

同样,触发器和行为也可以这样做(您可以清除它们)。
我认为对于隐式样式,只有在框架代码中才有相关内容。我们无法确定控件的默认样式是如何作为默认附加到控件的。

谢谢 - 我已经尝试将样式设置为 null,正如你所说,这可以解决显式样式的问题,但不能解决隐式样式的问题。清除行为和触发器也没有帮助。 - James Lavery
我已经将其标记为有用但不是答案,因为它并没有完全回答问题。(顺便说一下,在你发帖之前,我已经考虑并尝试了你的建议)。 - James Lavery

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接