导航页面时,所有UWP应用程序是否都会泄漏内存?

时间:2018-04-14 13:09:44

标签: .net memory-leaks uwp windows-10-universal

所以我在最新版本的Windows 10上使用VS2017 v15.6.4开始使用UWP并在C#中开发一个简单的应用程序。

运行应用程序时,我注意到它的内存使用量会随着时间的推移而持续增加。

经过大量的代码配对后,我得出结论,这是由页面导航调用引起的,例如:

Frame.Navigate(typeof SomePage);
Frame.GoBack();
Frame.GoForward();

创建和观察这个过程非常容易......

1)在VS2017中,创建一个新的空白应用程序(通用Windows)项目,称之为PageTest。

2)在项目中添加一个新的空白页,命名为“NewPage”。

3)将以下代码添加到MainPage.xaml.cs:

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace PageTest
{
    public sealed partial class MainPage : Page
    {
        DispatcherTimer timer = new DispatcherTimer();

        public MainPage()
        {
            InitializeComponent();
            timer.Interval = TimeSpan.FromSeconds(.01);
            timer.Tick += Timer_Tick;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            timer.Start();
        }

        private void Timer_Tick(object sender, object e)
        {
            timer.Stop();
            Frame.Navigate(typeof(NewPage));
        }
    }
}

4)将以下(几乎相同的)代码添加到NewPage.xaml.cs:

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace PageTest
{
    public sealed partial class NewPage : Page
    {
        DispatcherTimer timer = new DispatcherTimer();

        public NewPage()
        {
            InitializeComponent();
            timer.Interval = TimeSpan.FromSeconds(.01);
            timer.Tick += Timer_Tick;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            timer.Start();
        }

        private void Timer_Tick(object sender, object e)
        {
            timer.Stop();
            Frame.Navigate(typeof(MainPage));
        }
    }
}

你可以看到这个简单的测试应用程序包含2个页面,当它运行时,应用程序将自动在两页之间以每秒100次的速度(通过计时器)导航,直到你关闭应用程序。

5)构建并运行应用程序。还要运行任务管理器并记下应用程序的初始内存占用量。

6)去喝杯咖啡。当你回来时,你会看到内存使用量增长了。它会继续增长。

现在我知道这个例子是不现实的,但它纯粹是为了证明我怀疑是影响大多数(如果不是全部)UWP应用的基本问题。

试试这个......

运行Windows 10设置应用程序(由Microsoft开发的UWP应用程序)。再次,请注意它在任务管理器中的初始内存占用量。 (在我的工具包上,起始大约12.1 MB)。

然后反复单击系统设置图标...然后返回后退按钮...然后是系统设置图标...然后返回按钮...你明白了。并且观察内存占用也会增加。

执行此操作几分钟后,我的MS设置应用程序内存消耗量增加到超过90 MB。

此内存消耗似乎与UWP页面复杂性有关,如果您开始向页面添加大量XAML控件(尤其是图像控件),它会迅速上升。不久之后,我的功能丰富的UWP应用程序消耗1-2GB内存。

所以这个“问题”似乎会影响所有基于框架的UWP应用程序。我已经尝试过在3台不同的PC上使用其他UWP应用程序,我看到了同样的问题。

凭借我的功能丰富的应用程序,内存消耗已经非常糟糕,我现在正在考虑完全删除页面导航并将所有内容放在MainPage上。这不是一个愉快的想法。

无效的潜在解决方案......

我遇到过其他描述类似问题的文章,并提出了我尝试过的解决方案,这些解决方案没有任何区别......

1)将以下任一行添加到.xaml页面定义中没有帮助......

NavigationCacheMode="Required" 

NavigationCacheMode="Enabled" 

2)切换页面时手动强制垃圾回收无济于事。所以做这样的事情没有任何区别......

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    GC.Collect();
}

是否有人知道是否有解决方案,或者这是UWP应用的基本问题?

4 个答案:

答案 0 :(得分:4)

在提供的repro代码中,您继续向前导航,这将创建页面实例的无限导航后台堆栈(请检查Frame.BackStack.Count)。由于这些实例存储在内存中,因此应用程序的内存使用量自然会不受约束。

如果您更改代码以导航回MainPage,并因此将Backstack深度保持为2,则重复来回导航时内存将不会显着增长。

修改 但是,如果我们在更长的时间内观察到这一点,则会有可测量的内存增加(在我的测试中每个导航1.5KB)。这是平台代码中的已知泄漏,自Windows 10 Update 1803起尚未解决。

您的测试项目的更新版本在此处共享:

以下是NewPage.cs的代码:https://1drv.ms/u/s!AovTwKUMywTNoYVFL7LzamkzwfuRfg

public sealed partial class NewPage : Page
{
    DispatcherTimer timer = new DispatcherTimer();

    public NewPage()
    {
        InitializeComponent();
        timer.Interval = TimeSpan.FromSeconds(.01);
        timer.Tick += Timer_Tick;
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        timer.Start();
        long managedMem = GC.GetTotalMemory(true);
        ulong totalMem = Windows.System.MemoryManager.AppMemoryUsage;
        System.Diagnostics.Debug.WriteLine(string.Format("Managed Memory: {0} / Total Memory: {1}", managedMem, totalMem));
    }

    private void Timer_Tick(object sender, object e)
    {
        timer.Stop();
        Frame.GoBack();
    }
}

如果在您的真实应用程序中,您在几个导航周期后观察到MB大小泄漏,那么这不是由于上面提到的平台错误,而是由于需要在特定应用程序中调查的其他内容,使用VS例如,内存分析器。通常,应用程序代码中的循环引用或静态事件处理程序可能导致泄漏。调试这些内容的第一步是查看强制GC时页面的终结器是否按预期命中。如果没有,请使用VS内存分析工具来识别哪些对象正在泄漏,以及谁在坚持这样做。该数据将有助于查明特定案例的应用程序代码中的根本原因。通常,这些是由于循环引用,或静态事件处理程序未被取消订阅。如果您可以通过分析实际应用程序来分享信息,我们很乐意为您提供更多帮助。

答案 1 :(得分:1)

是的。这是UWP中的错误。我几个月前打开了一张Microsoft支持票,他们上周说他们发现了错误并解决了。他们将在Windows Insider预览版本以及下一个更新中发布此修复程序(所以我认为下周-在2018年12月21日仍不包括在内)。 Windows 10的春季更新将随附针对所有人的修复程序。

答案 2 :(得分:1)

尽管这是一则旧文章,但我还是将我的评论留在这里,以供其他可能会搜寻到它的人。

我们通过最新的UWP 6.2.9 Nuget更新在内存处理和GC调用方面进行了重大改进,同时将> = RS3作为目标(Win 10 1709)。完整的发行说明为here

答案 3 :(得分:0)

我知道这是一篇很老的文章,但我认为这对某人有帮助。导航时,我遇到了类似的行为。但它始终处于调试模式。导航时,我的应用程序在调试模式下甚至超过了(导航前为40Mb)100Mb。但最终发行产品中从未超过1Mb。