所以我在最新版本的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应用的基本问题?
答案 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。