在没有明确的延迟事件处理程序的情况下,如何在 MAUI 应用程序中弹出 ContentPage 时释放内存?

问题描述 投票:0回答:2

在我的应用程序中,当在 ContentPage (CP1) 上按下按钮时,我创建一个新的 ContentPage (CP2) 并将其推送到堆栈上,就像这样......

await Navigation.PushAsync(new CP2(param1, param2));

CP2 消耗大量内存,约 400MB。当显示 CP2 时,如果我单击后退箭头导航回 CP1,则不会释放内存。每次我从 CP1 导航到 CP2 时,当我从导航堆栈中弹出 CP2 时,会分配另外约 400MB 且不会释放。该应用程序很快就会因内存使用过多而被设备抛弃。 CP2 不订阅除其自身控件生成的事件之外的任何事件。它确实使用自定义构建的 ContentView。但是,该视图不订阅任何事件,也不使用任何非托管资源。

这是 CP2 的 xaml(实际名称为 MyWaxBoxAddItemsV):

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:custom_components="clr-namespace:FasterWaxer.CustomComponents"
             x:Class="FasterWaxer.MyWaxBoxAddItemsV"
             Title="MyWaxBoxAddItemsV">
    
    <CollectionView Grid.Row="0" ItemsSource="{Binding BrandCatalog}" Margin="7,0,5,0">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <Grid RowDefinitions="65" ColumnDefinitions="*,60">
                    <!--<custom_components:CatalogItem Grid.Column="0" />-->
                    <Grid Grid.Column="1" VerticalOptions="Center" WidthRequest="50" HeightRequest="50" HorizontalOptions="End">
                        <Grid.GestureRecognizers>
                            <TapGestureRecognizer Tapped="OnAddWaxBoxItemTapped" CommandParameter="{Binding}"/>
                        </Grid.GestureRecognizers>
                    <Image Source="{Binding AddActionIconFileName}" Margin="0,0,5,0" VerticalOptions="Center" HeightRequest="23" WidthRequest="28" HorizontalOptions="End" />
                    </Grid>
                    <BoxView HeightRequest="1" Grid.ColumnSpan="2" VerticalOptions="End"/>
                </Grid>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

下面是定义 CP2 订阅的唯一事件处理程序的代码:

public partial class MyWaxBoxAddItemsV : ContentPage
{
    private readonly MyWaxBoxAddItemsVM vm;

    public MyWaxBoxAddItemsV(MyWaxBoxVM waxBox, WaxBrandCatalogItemVM brandCatalog)
    {
        vm = new MyWaxBoxAddItemsVM(waxBox, brandCatalog);
        InitializeComponent();
        BindingContext = vm;
    }

    private async void OnAddWaxBoxItemTapped(object sender, TappedEventArgs e)
    {
        if (e.Parameter == null) return;
        var item = (WaxCatalogItemVM)e.Parameter;

        if (item.IsInMyWaxBox)
        {
            string prompt = new($"Remove {item.BrandName} {item.ModelName}?");
            if (await DisplayAlert(prompt, string.Empty, "Remove", "Cancel"))
            {
                vm.WaxBox.RemoveItem(item);
            }
        }
        else
        {
            vm.WaxBox.AddItem(item);
        }

        return;
    }
}

custom_components:CatalogItem 是一个 ContentView,显示一堆格式化数据。你可以看到,我在上面的xaml中注释掉了。当我这样做时,每次渲染 CP2 时的内存消耗都会减少。然而,内存仍然没有被释放。

MyWaxBoxAddItemsVM(“CP2”的 ViewModel)中有 ObservableObjects 和 ObservableCollections。 CP2 MyWaxBoxAddItemsVM 层次结构中没有事件处理程序。

我花了几个小时翻阅 Microsoft 文章、stackoverflow 帖子等。我看到了很多与使用 IDisposable 和其他解决方案相关的信息,这些信息几乎都与取消订阅事件处理程序相关。就我而言,我没有任何我知道的可以取消订阅的事件处理程序。其他类中的事件处理程序可以更改属于 CP2 ViewModel 一部分的 ObservableObject。我一直在想我的问题可能与此有关。 关于为什么从导航堆栈中弹出 CP2 时内存没有被释放的任何指导?这是否与 CP2 的层次结构中包含 ObservableObjects 有关? CP2 弹出时如何释放内存?

7 月 2 日:添加有关我尝试过的其他内容的信息...

我尝试将 MyWaxBoxAddItemsV (CP2) 实现为 IDisposable。 Dispose() 将 vm 和 BindingContext 设置为 null。在创建 CP2 的新实例之前,CP1 对 CP2 的前一个实例调用 MyWaxBoxAddItemsV.Dispose()。这不会导致内存消耗模式发生变化。

一如既往,我将非常感谢您的指导,帮助我找到解决方案。

memory-management navigation maui
2个回答
1
投票

我刚刚搜索了“毛伊岛内存管理”,发现了几个与我遇到的可怕内存泄漏相关的错误报告。您可以在这里看到它们:滚动时 CollectionView 中的大量内存泄漏到处都有内存泄漏[核心]修复绑定中的内存泄漏

据称最新的 .NET/MAUI 预览版 (8.0.0-preview.5.8529) 中已包含修复程序。我安装了此 SDK,但是,我使用的是最新版本的 Visual Studio for Mac,它与 .NET 8.0 不兼容。所以,我还无法看到问题是否已经解决。一旦我了解更多信息或找到解决方案,我会立即向这里报告。


0
投票

我最终使用了 Adam Essenmacher 的 AdamE.MemoryToolkit.Maui。它对我来说是一个救星(应用程序保护程序)。解决了我所有的内存泄漏问题。我刚刚迁移到 .NET 9.0,必须看看内存问题是否仍然存在。

© www.soinside.com 2019 - 2024. All rights reserved.