Пользовательские контроли создаются динамически во время выполнения, но имеет утечку памяти - PullRequest
1 голос
/ 07 ноября 2011

Мое приложение разработано MVVM.

Главное окно - MainWindow.xaml, как показано ниже. Главное окно имеет два пользовательских элемента управления.

Кстати, usercontrol создается динамически во время выполнения, когда изменяется свойство viewmodel. Но, похоже, у моего приложения есть утечка памяти.

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");
    }

}

Функция ChangeView файла MainViewModel.cs меняет свойство ViewType каждую секунду. При изменении свойства ViewType, ui1ViewModel создается как новый экземпляр. Если экземпляр ui1ViewModel будет создан в следующий раз, я ожидаю, что старый экземпляр ui1ViewModel будет удален сборщиком мусора.

Но, похоже, приложение испытывает утечку памяти при тестировании несколько раз. Я проверил деструктор ui1ViewModel и введите Debug.WriteLine ("Call Destructor") в деструкторе. но он не звонит каждый раз. Когда я вызываю GC.Collect () принудительно, вызывается деструктор ui1ViewModel и уменьшает объем памяти приложения.

Итак, мой вопрос

Могу ли я вызвать GC.collect () принудительно в этом случае? или у вас есть другой способ решить эту проблему?

1 Ответ

2 голосов
/ 07 ноября 2011

Я тоже не думаю, что это утечка памяти:

Правильно написанная программа не может предполагать, что финализаторы когда-либо бежать.

У Раймонда Чена есть хорошее объяснение того, что люди неправильно понимают под сборкой мусора http://blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx

Я всегда буду помнить это:

Сборка мусора моделирует компьютер с бесконечным количеством объем памяти. Остальное - механизм.

...