我正在为Windows Phone 7开发Silverlight中的一个应用程序。我陷入了Windows手机应用程序中常见的问题,但无法以任何方式摆脱它。从第一页到第二页,第二页到第一页等导航过程中会出现内存泄漏问题,等等多次出现。
要解决这个问题,我创建了一个有2个空白页面的新项目。每页有2个文本块用于打印当前内存和峰值内存,还有一个按钮用于移动到下一页或上一页。当从第1页导航到第2页时,我对所有3个内容进行null referance并调用gc.collect来销毁页面referance。同样的,当从第2页移到第1页时,我也会做同样的事情。
我还尝试在计时器中每500毫秒调用gc.collect(),但仍然没有结果。如果我完全删除gc.collect(),内存增加MB,所以我认为这是必须的。
以下是我的代码片段:
主页:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using System.Windows.Threading;
namespace AppMemory
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
txtCM.Text = "C : " + Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage.ToString();
txtPM.Text = "P: " + Microsoft.Phone.Info.DeviceStatus.ApplicationPeakMemoryUsage.ToString();
}
// Simple button Click event handler to take us to the second page
private void Button_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Page1.xaml", UriKind.Relative));
}
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
while (this.NavigationService.BackStack.Any())
{
this.NavigationService.RemoveBackEntry();
}
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
while (this.NavigationService.BackStack.Any())
{
this.NavigationService.RemoveBackEntry();
}
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
dosposeMemory();
base.OnNavigatedFrom(e);
this.DataContext = null;
GC.Collect();
}
public void dosposeMemory()
{
try
{
if (txtCM != null)
{
txtCM.Text = null;
txtCM = null;
}
if (txtPM != null)
{
txtPM.Text = null;
txtPM = null;
}
if (btn1 != null)
{
btn1.Click -= Button_Click;
btn1.Style = null;
btn1.Resources.Clear();
btn1.Resources = null;
btn1 = null;
}
if (ContentPanel != null)
{
ContentPanel.Children.Clear();
ContentPanel.Resources.Clear();
ContentPanel.Resources = null;
ContentPanel = null;
}
if (LayoutRoot != null)
{
LayoutRoot.DataContext = null;
LayoutRoot.Background = null;
LayoutRoot.Resources.Clear();
LayoutRoot.Resources = null;
LayoutRoot.Children.Clear();
LayoutRoot = null;
}
if (app1 != null)
{
app1.Resources.Clear();
app1.Resources = null;
app1 = null;
}
GC.Collect();
}
catch(Exception)
{
}
}
~MainPage()
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(new System.Action(() =>
{
GC.Collect();
}));
}
}
}
第二页:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
namespace AppMemory
{
public partial class Page1 : PhoneApplicationPage
{
public Page1()
{
InitializeComponent();
textBlock1.Text = "C : " + Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage.ToString();
textBlock2.Text = "P: " + Microsoft.Phone.Info.DeviceStatus.ApplicationPeakMemoryUsage.ToString();
}
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
while (this.NavigationService.BackStack.Any())
{
this.NavigationService.RemoveBackEntry();
}
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
while (this.NavigationService.BackStack.Any())
{
this.NavigationService.RemoveBackEntry();
}
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
dosposeMemory();
base.OnNavigatedFrom(e);
this.DataContext = null;
GC.Collect();
}
public void dosposeMemory()
{
try
{
if (textBlock1 != null)
{
textBlock1.Text = null;
textBlock1 = null;
}
if (textBlock2 != null)
{
textBlock2.Text = null;
textBlock2 = null;
}
if (ContentPanel != null)
{
ContentPanel.Children.Clear();
ContentPanel.Resources.Clear();
ContentPanel.Resources = null;
ContentPanel = null;
}
if (LayoutRoot != null)
{
LayoutRoot.Children.Clear();
LayoutRoot.Resources.Clear();
LayoutRoot.Resources = null;
LayoutRoot = null;
}
if (page1 != null)
{
page1.Resources.Clear();
page1.Resources = null;
page1 = null;
}
GC.Collect();
}
catch (Exception)
{
GC.Collect();
}
}
}
}
以下是对每次尝试增加的当前记忆的跟踪:
Try Page 1 Page 2
1 7426048 7442432
2 6959104 8257536
3 6934528 8454144
4 8622080 8458240
5 8626176 8470528
6 8630272 8470528
问题: 1)我的流程和方法是否适合导航和管理内存? 2)我的方法是为文本块和按钮设置referance null是否合适? 3)同样在我的实际项目中,我在列表框中使用数据绑定,我已经按照以下方式进行了搜索。
if (listCountry != null)
{
listCountry.SelectionChanged -= listCountry_SelectionChanged;
//listCountry.Items.Clear();
listCountry.DataContext = null;
listCountry.ItemsSource = null;
listCountry.Resources.Clear();
listCountry.Resources = null;
listCountry = null;
}
我对此有疑问,因为在我的项目中,这种列表框有多种用法。
请带我离开,因为我花了很多时间进行研究和更新,但没有得到当前和峰值内存的解决方案。
提前致谢。 大卫雅各布斯。
答案 0 :(得分:1)
我在开发WP8应用时遇到了同样的问题。当您覆盖OnBackKeyPress
方法时,在第二页上确切地说,您需要从堆栈中删除页面(或JournalEntry
),因为如果不这样做,则将其保留在堆栈中不能被GC拿起。您需要将NavigationService.RemoveBackEntry();
添加到OnBackKeyPress
方法,首先调用NavigationService.RemoveBackEntry();
然后执行您想要的操作非常重要。