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

查看:16
本文介绍了是否所有 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 Settings 应用内存消耗上升到 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 Update 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​​KUMywTNoYVFL7LzamkzwfuRf

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 应用在导航页面时都会泄漏内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆