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

Do all UWP apps leak memory when navigating pages?(导航页面时是否所有 UWP 应用都会泄漏内存?)

本文介绍了导航页面时是否所有 UWP 应用都会泄漏内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我一直在深入研究 UWP,并在最新版本的 Windows 10 上使用 VS2017 v15.6.4 用 C# 开发一个简单的应用程序.

So I've been getting my teeth into UWP and developing a simple app in C# using VS2017 v15.6.4, on the latest release of Windows 10.

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

When running the app I notice its memory usage continues to increase over time.

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

After a lot of pairing back of the code, I've come to the conclusion that this is being caused by page navigation calls, such as:

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

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

It is very easy to create and observe this process...

1)在VS2017中,新建一个Blank App(Universal Windows)项目,命名为PageTest.

1) In VS2017, create a new Blank App (Universal Windows) project, call it PageTest.

2) 向项目添加一个新的空白页面,将其命名为NewPage".

2) Add a new Blank Page to the project, naming it 'NewPage'.

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

3) Add the following code to the 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:

4) Add the following (almost identical) code to 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 次的速度(通过计时器)自动在两个页面之间导航,直到您关闭应用.

You can see that this simple test app contains 2 pages, and when it runs, the app will automatically navigate between the two pages at the rate of 100 times per second (via the timers) until you close the app.

5) 构建并运行应用程序.同时运行任务管理器并记下应用的初始内存占用.

5) Build and run the app. Also run Task Manager and note the app's initial memory footprint.

6) 去泡杯咖啡.当你回来时,你会看到内存使用量增加了.而且还会继续增长.

6) Go and make a cup of coffee. When you come back you'll see the memory usage has grown. And it will continue to grow.

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

Now I know this example is unrealistic, but it is here purely to demonstrate what I suspect is a fundamental problem affecting most (if not all) UWP apps.

试试这个...

运行 Windows 10 设置应用(由 Microsoft 开发的 UWP 应用).同样,请注意它是任务管理器中的初始内存占用.(在我的工具包中,它从大约 12.1 MB 开始).

Run the Windows 10 Settings app (a UWP app developed by Microsoft). Again, note it's initial memory footprint in Task Manager. (On my kit this starts at about 12.1 MB).

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

Then repeatedly click on the System Settings icon... then the Back button... then the System Settings icon... then the Back button... You get the idea. And watch the memory footprint also increase.

这样做几分钟后,我的 MS 设置应用程序内存消耗上升到超过 90 MB.

After a few minutes of doing this, my MS Settings app memory consumption went up to over 90 MB.

这种内存消耗似乎与 UWP 页面复杂性有关,如果您开始向页面添加大量 XAML 控件,尤其是图像控件,它会迅速增加.我的功能丰富的 UWP 应用很快就会消耗 1-2GB 内存.

This memory consumption seems to be related to UWP page complexity and it goes up rapidly if you start adding a lot of XAML controls to your pages, especially Image controls. And it doesn't take long before my feature rich UWP app is consuming 1-2GB memory.

所以这个问题"似乎会影响所有基于框架的 UWP 应用.我已经在 3 台不同的 PC 上尝试了其他 UWP 应用程序,但我发现它们都存在相同的问题.

So this 'problem' seems to affect all frame based UWP apps. I've tried it with other UWP apps on 3 different PC's and I see the same problem on them all.

使用我的功能丰富的应用程序,内存消耗变得如此糟糕,以至于我现在正在考虑完全取消页面导航并将所有内容放在 MainPage 上.这不是一个令人愉快的想法.

With my feature rich app, memory consumption has got so bad that I'm now considering scrapping Page navigation altogether and putting everything on the MainPage. Which is not a pleasant thought.

行不通的潜在解决方案...

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

I've come across other articles describing a similar issue and there are proposed solutions that I've tried, which don't make any difference...

1) 将以下任一行添加到 .xaml 页面定义都无济于事...

1) Adding either of the following lines to the .xaml page definitions does not help...

NavigationCacheMode="Required" 

NavigationCacheMode="Enabled" 

2) 切换页面时手动强制垃圾回收没有帮助.所以做这样的事情没有区别......

2) Manually forcing garbage collection when switching pages does not help. So doing something like this makes no difference...

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

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

推荐答案

在提供的重现代码中,您继续向前导航,这将创建一个无限的页面实例导航回栈(检查 Frame.BackStack.Count).由于这些实例存储在内存中,因此应用的内存使用量自然会无限增长.

In the repro code provided you keep navigating forward, which will create an infinite navigation backstack of page instances (check Frame.BackStack.Count). Since those instances are stored in memory the app's memory usage will naturally grow unbound.

如果您更改代码以导航回 MainPage,并因此将 backstack 深度保持为 2,则内存不会随着反复来回导航而显着增长.

If you change the code to navigate back to MainPage, and therefore keep the backstack depth at 2, the memory will not grow noticeably with repeated back and forth navigation.

编辑但是,如果我们在较长时间内观察到这一点,内存就会显着增加(在我的测试中,每次导航 1.5KB).这是平台代码中的一个已知泄漏,截至 Windows 10 更新 1803 尚未解决.

EDIT However, if we observe this over a longer period of time there is a measurable increase of memory (1.5KB per navigation in my testing). This is a known leak in platform code that has not yet been addressed as of Windows 10 Update 1803.

您的测试项目的更新版本在这里共享:

The updated version of your test project is shared here:

这是 NewPage.cs 的代码:https://1drv.ms/u/s!AovTw​​KUMywTNoYVFL7LzamkzwfuRfg

Here is the code for 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 内存分析工具来确定哪些对象正在泄漏以及谁在保留它.该数据将有助于查明该特定案例的应用程序代码中的根本原因.通常这些是由于循环引用或未取消订阅的静态事件处理程序.如果您可以通过分析实际应用分享信息,我们很乐意在这方面提供更多帮助.

If in your real app you observe a MB size leak after just a couple of navigation cycles then this is not due to above mentioned platform bug, but due to something else that needs to be investigated in the specific app, with the VS memory profiler for example. Often times leaks can be caused due to circular references or static event handlers in the app code. A good first step to debug these would be see if the page's finalizer gets hit as expected when forcing a GC. if not, use the VS memory profiling tools to identify what objects are being leaked and who is holding on to that. That data will help to pinpoint the root cause in the app code for that specific case. Typically those are due to circular references, or static event handlers not being unsubscribed. Happy to help more with this if you can share info from profiling the actual app.

这篇关于导航页面时是否所有 UWP 应用都会泄漏内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:导航页面时是否所有 UWP 应用都会泄漏内存?

基础教程推荐