【发布时间】:2011-11-07 05:43:40
【问题描述】:
我的应用程序由 MVVM 设计。
主窗口是 MainWindow.xaml,如下所示。主窗口有两个用户控件。
顺便说一句,用户控件是在运行时动态创建的,当视图模型的属性发生变化时。 但似乎我的应用程序有内存泄漏。
MainWindow.xaml
<Window x:Class="InstanceTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InstanceTest"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MainWindowViewModel x:Key="MainWindowViewModel" />
<DataTemplate x:Key="UD1">
<ContentControl>
<local:UserControl1></local:UserControl1>
</ContentControl>
</DataTemplate>
<DataTemplate x:Key="UD2">
<ContentControl>
<local:UserControl2></local:UserControl2>
</ContentControl>
</DataTemplate>
<DataTemplate x:Key="contentsTemplate">
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding ViewType}" Value="1">
<Setter Property="ContentTemplate" Value="{DynamicResource UD1}" />
</DataTrigger>
<DataTrigger Binding="{Binding ViewType}" Value="2">
<Setter Property="ContentTemplate" Value="{DynamicResource UD2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</Window.Resources>
<Grid DataContext="{StaticResource MainWindowViewModel}">
<StackPanel>
<Button Height="30" Command="{Binding ChangeViewCommand}">ChangeView</Button>
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource contentsTemplate}" />
</StackPanel>
</Grid>
MainWindow.xaml 与 MainWindowViewModel.cs 相关。 根据 ViewType 属性,每个用户控件都是在运行时动态创建的。
public class MainWindowViewModel : ViewModelBase
{
private string viewType;
public string ViewType
{
get { return viewType; }
set
{
viewType = value;
base.RaisePropertyChanged(() => this.ViewType);
}
}
public MainWindowViewModel()
{
ChangeViewCommand = new RelayCommand(ChangeView);
}
public ICommand ChangeViewCommand { get; private set; }
private void ChangeView(object o)
{
int aa = 1000;
while (aa > 0)
{
System.Threading.Thread.Sleep(1000);
System.Windows.Forms.Application.DoEvents();
if (ViewType == "1")
ViewType = "2";
else
ViewType = "1";
aa--;
//GC.Collect();
}
}
}
UserControl1.xaml
<UserControl.Resources>
<local:uc1ViewModel x:Key="uc1ViewModel" />
</UserControl.Resources>
<Grid DataContext="{StaticResource uc1ViewModel}">
<StackPanel>
<TextBlock FontSize="30" Text="{Binding TextExample}"></TextBlock>
<Image Source="/InstanceTest;component/Images/sample.jpg" />
</StackPanel>
</Grid>
UserControl1.xaml 有 uc1ViewModel.cs。 UserControl2.xaml 的 uc2ViewModel.cs 如下。
public class uc1ViewModel : ViewModelBase
{
private string textExample;
public string TextExample
{
get { return textExample; }
set
{
textExample = value;
base.RaisePropertyChanged(() => this.TextExample);
}
}
public uc1ViewModel()
{
TextExample = "UD1...";
}
~uc1ViewModel()
{
Debug.WriteLine("Call Destructor");
}
}
MainViewModel.cs 的ChangeView 函数每秒更改一次ViewType 属性。 当更改 ViewType 的属性时,ui1ViewModel 被创建为新实例。如果下次创建 ui1ViewModel 的实例,我希望 ui1ViewModel 的旧实例会被垃圾收集器删除。
但是,在多次测试时,应用程序似乎存在内存泄漏。 我检查了 ui1ViewModel 的析构函数 并在析构函数中键入 Debug.WriteLine("Call Destructor")。但它不会每次都打电话。 当我强制调用 GC.Collect() 时,会调用 ui1ViewModel 的析构函数并减少应用程序的内存大小。
所以,我的问题是
在这种情况下我可以强制调用 GC.collect() 吗?或者您有其他方法可以解决这个问题吗?
【问题讨论】:
-
作为DataContext="{StaticResource uc1ViewModel}",每次都分配uc1ViewModel。那么我是否必须调用 GC.Collect() 才不会发生内存泄漏?
-
不,事实上,手动调用 GC.Collect 无法防止内存泄漏。请阅读我上次评论中提供的链接。您很可能没有内存泄漏。如果您害怕自己有一个,那么请长时间分析您的内存消耗
-
我怕内存泄漏的原因是我已经测试了很长时间了。应用程序的内存从 25M 开始。除手动 GC.Collect() 外,内存最大为 35M。我已经用 Windbg 和分析器查找了该程序以找到原因。
-
@Dianwater - 我检查了你的样本,没有任何内存泄漏。知道看起来合适的 GC RESERVCES 内存。这取决于您的系统配置、可用内存、内存使用情况等。在适当的情况下,保留 200+ mb 的内存一点也不奇怪。