【问题标题】:Usercontrols are created dynamically in run-time, but It has memory leak用户控件在运行时动态创建,但存在内存泄漏
【发布时间】: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 的内存一点也不奇怪。

标签: c# wpf mvvm prism


【解决方案1】:

我也不认为是内存泄漏:

一个正确编写的程序不能假设终结器永远 运行。

Raymond Chen 很好地解释了人们对垃圾收集的错误理解: http://blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx

我会永远记住这一点:

垃圾收集是模拟一台拥有无限量的计算机 记忆。剩下的就是机制了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多