我正在Silverlight 中为Windows Phone 7 开发一个应用程序。我陷入了Windows Phone 应用程序中非常常见的问题,但无法以任何方式摆脱它。这是从第一页到第二页、从第二页到第一页等多次导航时出现的内存泄漏问题。
为了解决这个问题,我创建了一个有 2 个空白页的新项目。每页有 2 个文本块用于打印当前内存和峰值内存,以及一个用于移动到下一页或上一页的按钮。当从第 1 页导航到第 2 页时,我对所有 3 件事进行空引用并调用 gc.collect 来销毁页面引用。同样,从第 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) 我为文本块和按钮设置引用为空的方法是否正确?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;
}
我对此表示怀疑,因为在我的项目中,这种列表框有多种用法。
请带我离开,因为我花了很多时间进行研究和更新,但没有找到当前和峰值内存的解决方案。
提前致谢。大卫雅各布斯。