4

我花了很多时间试图在 Android 上的 Xamarin.Forms 应用程序中追踪内存泄漏。在经历了很多死胡同和虚假黎明之后,我想我可能遇到了导致问题的东西。

使用 Xamarin Profiler,我可以看到,一旦我创建了一个 Style 并将其应用于控件(或者实际上只是一个隐式样式),我们就会得到 Multiple WeakReferences 保持“活动” - 即没有垃圾收集。

请注意,我假设它们引用的对象已被 GC 处理(因为对对象的引用是weak),但 WeakReferences本身仍然存在。

现在当然 WeakReferences 很小,我知道 - 但是当您在页面推送/弹出的每次迭代中创建数百个时,内存就会增加,我们就会有严重的泄漏。

这是详细信息。使用 Xamarin.Forms 2.3.4.270(我们尚未升级,因为我们想保留已知问题!)在 Android - 物理设备上运行。

应用程序.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 个弱引用。深入了解这些节目:

有趣的是,这些 WeakReference 似乎是作为 Behavior 和 Trigger 附加的一部分创建的。查看顶部的调用树给出:

因此,WeakReference 似乎是作为设置 BindableObject 的值和样式的后续设置的一部分而创建的。

而且似乎 WeakReference 仍在内存中并被某些东西引用 - 行为集合?

使用 Profiler,我可以看到我们没有剩余未 GC 的标签。它似乎在主题/行为/触发器处理中。

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

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

4

1 回答 1

1

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

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

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

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

    base.OnDisappearing();
}

触发器和行为也可以这样做(您可以清除它们)。

我认为对于隐式样式,只有框架代码中有一些东西。我们无法确定默认样式的控件是如何与默认控件关联的。

于 2018-01-04T02:47:47.650 回答