FNU Amit Kumar Ответов: 0

Утечка памяти со словарем общих ресурсов


I am working on a Large wpf applications, We opted for Shared Resource Dictionary because ResourceDictionaries are always instantiated, everytime they are found in an XAML we might end up having one resource dictionary multiple times in memory. Get benifitted from this and cut down from 800mb down to 50mb, which is a really huge , Unfortunately this leads to memory leak. I figured this happens to everything that is instantiated via XAML like converters, user controls etc are kept in memory. and when i remove the converter and user control, it works fine. How can i avoid the memory leak using the shared resource dictionary.Thank you
The memory leak xaml is commented out in code


Что я уже пробовал:

<pre lang="XML">
<UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <utility:SharedResourceDictionary SharedSource="/Arinc.UI.Common;component/Styles/GlobalStylesResources.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <converters:GridLengthToDoubleConverter x:Key="gridLengthConverter"/>
        </ResourceDictionary>
    </UserControl.Resources>
	
	 <DataGrid>
	 <!-- Memory Leak xaml
		<DataGridTextColumn MinWidth="140" Header="STATE" Binding="{Binding IncidentStateText}" CellStyle="{StaticResource BlinkingCellStyle}">
			<DataGridTextColumn.ElementStyle>
				<Style TargetType="{x:Type TextBlock}">
					<Setter Property="Foreground" Value="{Binding IncidentStateTextColor, Converter={StaticResource ColorToBrushConverter}}"/>
					<Setter Property="VerticalAlignment" Value="Center"/>
				</Style>
			</DataGridTextColumn.ElementStyle>
		</DataGridTextColumn>
		
		<DataGridTemplateColumn MinWidth="200" Header="DATE/TIME" SortDirection="Descending" CellStyle="{StaticResource BlinkingCellStyle}" SortMemberPath="Time">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <commonControls:DateTimeDisplayControl Content="{Binding Time}" DisplayFormat="ShortDateLongTime" Foreground="{Binding TimeColor, Converter={StaticResource ColorToBrushConverter}}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
		-->		
		
		<DataGridTextColumn Width="200" Header="DATE/TIME" Binding="{Binding Time, StringFormat='G'}" CellStyle="{StaticResource BlinkingCellStyle}" SortDirection="Descending" SortMemberPath="Time">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="{x:Type TextBlock}">						
                    <!--<Setter Property="Foreground" Value="{Binding TimeColor, Converter={StaticResource ColorToBrushConverter}}"/>-->
                    <Setter Property="VerticalAlignment" Value="Center"/>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
		
		 <DataGridTextColumn Width="200" Header="DATE/TIME" Binding="{Binding Time, StringFormat='G'}" CellStyle="{StaticResource BlinkingCellStyle}" SortDirection="Descending" SortMemberPath="Time">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="{x:Type TextBlock}">
                    <!--<Setter Property="Foreground" Value="{Binding TimeColor, Converter={StaticResource ColorToBrushConverter}}"/>-->
                    <Setter Property="VerticalAlignment" Value="Center"/>
                </Style>
            </DataGridTextColumn.ElementStyle>
		</DataGridTextColumn>
				
	  </DataGrid>
</pre>


/// <summary>
/// Loads singleton instance of ResourceDictionary to current scope;
/// </summary>
public class SharedResourceDictionary : ResourceDictionary
{
  /// <summary>
  /// store weak references to loaded ResourceDictionary, to ensure that ResourceDictionary won't be instanciated multiple times
  /// </summary>
  protected static Dictionary<string, WeakReference> SharedResources = new Dictionary<string, WeakReference>();

  public string SharedSource
  {
    get { return _SharedSource; }
    set
    {
      if (_SharedSource != value)
      {
        _SharedSource = value;
        sharedSourceChanged();
      }
    }
  }
  private string _SharedSource;


  private void sharedSourceChanged()
  {
    //ResourceDictionary will be instanciated only once
    ResourceDictionary sharedResourceDictionary;

    lock (SharedResources)
    {
      WeakReference weakResourceDictionary = null;
      if (SharedResources.ContainsKey(_SharedSource))
      {
        weakResourceDictionary = SharedResources[_SharedSource];
      }
      else
      {
        SharedResources.Add(_SharedSource, null);
      }

      if (weakResourceDictionary == null || !weakResourceDictionary.IsAlive) //load ResourceDictionary or get reference to exiting
      {
        sharedResourceDictionary = (ResourceDictionary)Application.LoadComponent(new Uri(_SharedSource, UriKind.Relative));
        weakResourceDictionary = new WeakReference(sharedResourceDictionary);
      }
      else
      {
        sharedResourceDictionary = (ResourceDictionary)weakResourceDictionary.Target;
      }

      SharedResources[_SharedSource] = weakResourceDictionary;
    }


    if (Application.Current != null)
    {
      //if sharedResourceDictionary is defined in application scope do not add it to again to current scope
      if (containsResourceDictionary(Application.Current.Resources, sharedResourceDictionary))
      {
        return;
      }
    }

    this.MergedDictionaries.Add(sharedResourceDictionary);
  }

  private bool containsResourceDictionary(ResourceDictionary scope, ResourceDictionary rs)
  {
    foreach (var subScope in scope.MergedDictionaries)
    {
      if (subScope == rs) return true;
      if (containsResourceDictionary(subScope, rs)) return true;
    }
    return false;
  }
}

0 Ответов