Speicherleck bei der Verwendung von SharedResourceDictionary

wenn Sie arbeitete einige größere wpf-Anwendungen, die Sie möglicherweise vertraut mit diese. Da ResourceDictionaries immer instanziiert werden, jedesmal, wenn Sie gefunden werden, in einer XAML-wir könnten am Ende mit einem resource dictionary mehrfach im Speicher. Also die oben genannte Lösung scheint eine sehr gute alternative. In der Tat für unser Aktuelles Projekt dieser trick hat ... viel Speicher Verbrauch von 800 MB runter zu 44mb, das ist eine wirklich gewaltige Auswirkungen. Leider ist diese Lösung kommt zu einem Preis, dem möchte ich hier zeigen, und hoffentlich einen Weg finden, es zu vermeiden, während immer noch die SharedResourceDictionary.

Machte ich ein kleines Beispiel zu visualisieren, das problem mit einer shared resource dictionary.

Nur das erstellen einer einfachen WPF-Anwendung. Fügen Sie eine Ressource Xaml

Geteilt.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <SolidColorBrush x:Key="myBrush" Color="Yellow"/>

</ResourceDictionary>

Nun fügen Sie ein Benutzersteuerelement. Der codebehind ist nur die default, also habe ich einfach nur zeigen, die xaml -

MyUserControl.xaml

<UserControl x:Class="Leak.MyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             xmlns:SharedResourceDictionary="clr-namespace:Articy.SharedResourceDictionary" Height="128" Width="128">

    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Leak;component/Shared.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

    <Grid>
        <Rectangle Fill="{StaticResource myBrush}"/>     
    </Grid>
</UserControl>

Den Fenster-code hinter so aussieht

Window1.xaml.cs

//[ ... ]
    public Window1()
    {
        InitializeComponent();
        myTabs.ItemsSource = mItems;
    }

    private ObservableCollection<string> mItems = new ObservableCollection<string>();

    private void OnAdd(object aSender, RoutedEventArgs aE)
    {
        mItems.Add("Test");
    }
    private void OnRemove(object aSender, RoutedEventArgs aE)
    {
        mItems.RemoveAt(mItems.Count - 1);
    }

Und das Fenster in xaml wie diese

Window1.xaml

    <Window.Resources>
        <DataTemplate x:Key="myTemplate" DataType="{x:Type System:String}">
            <Leak:MyUserControl/>
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <DockPanel>
            <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
                <Button Content="Add" Click="OnAdd"/>
                <Button Content="Remove" Click="OnRemove"/>
            </StackPanel>
            <TabControl x:Name="myTabs" ContentTemplate="{StaticResource myTemplate}">
            </TabControl>
        </DockPanel>
    </Grid>
</Window>

Ich weiß, das Programm ist nicht perfekt und vermutlich erleichtert werden könnte, während aber herauszufinden, ein Weg, um das problem anzeigen, das ist, was ich kam mit. Trotzdem:

Starten Sie diese und prüfen Sie den Speicherverbrauch, wenn Sie einen memory-profiler-dies wird viel einfacher. Fügen Sie (mit dem zeigen Sie es durch einen Klick auf das Register) und entfernen eine Seite und du wirst sehen, alles funktioniert einwandfrei. Nichts leckt.
Jetzt in der UserControl.Resources Abschnitt wird die SharedResourceDictionary statt der ResourceDictionary gehören die Geteilt.xaml. Sie werden sehen, dass die MyUserControl wird in Erinnerung bleiben, nachdem Sie entfernt einen Seite, und die MyUserControl im es.

Ich dachte, das passiert alles instanziert ist über XAML-Wandler, Bedienelemente, etc. Merkwürdigerweise ist das nicht geschehen, auf Benutzerdefinierte Steuerelemente. Meine Vermutung ist, weil nichts wirklich instanziiert, auf benutzerdefinierte Steuerelemente, Daten, Vorlagen und so weiter.

Also Erstens, wie können wir es vermeiden? In unserem Fall mit SharedResourceDictionary ist ein muss, aber die Speicherverluste macht es unmöglich, zu verwenden es produktiv.
Den Verlust kann vermieden werden, mithilfe von CustomControls statt Benutzersteuerelemente, das ist nicht immer praktisch. Also, warum sind Benutzersteuerelemente starke verwiesen wird, die von einem ResourceDictionary?
Ich Frage mich, warum noch niemand erlebt, wie ich schon in einer älteren Frage, es scheint, wie wir Ressourcen verwenden Wörterbücher und XAML absolut falsch, sonst Frage ich mich, warum Sie so inefficent.

Ich hoffe, jemand kann etwas Licht auf diese Angelegenheit.

Vielen Dank im Voraus
Nico

  • In Ihrem memory-profiler, was für ein Objekt hielt den Verweis auf die MyUserControl Instanz?
  • Ich kann mich nicht erinnern, sicher, aber ich bin fast sicher, es war ein ResourceDictionary, sowie in meinem Fall ein SharedResourceDictionary.
InformationsquelleAutor dowhilefor | 2011-07-28
Schreibe einen Kommentar