2011-07-28 14 views
10

का उपयोग करते समय मेमोरी लीक यदि आपने कुछ बड़े wpf अनुप्रयोगों पर काम किया है तो आप this से परिचित हो सकते हैं। चूंकि संसाधन शब्दकोश हमेशा तत्काल होते हैं, हर बार जब वे XAML में पाए जाते हैं तो हम स्मृति में एक संसाधन शब्दकोश को कई बार समाप्त कर सकते हैं। तो उपर्युक्त समाधान एक बहुत अच्छा विकल्प की तरह लगता है। असल में हमारे वर्तमान प्रोजेक्ट के लिए इस चाल ने बहुत कुछ किया ... 800 एमबी से 44 एमबी तक मेमोरी खपत, जो वास्तव में एक बड़ा प्रभाव है। दुर्भाग्यवश यह समाधान एक लागत पर आता है, जिसे मैं यहां दिखाना चाहता हूं, और उम्मीद है कि SharedResourceDictionary का उपयोग करते समय इसे टालने का एक तरीका ढूंढें।ShareResourceDictionary

मैंने साझा संसाधन शब्दकोश के साथ समस्या को देखने के लिए एक छोटा सा उदाहरण बनाया।

बस एक साधारण WPF एप्लिकेशन बनाएं। एक संसाधन Xaml

Shared.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> 

जोड़ें एक UserControl जोड़ें। codebehind बस डिफ़ॉल्ट है, इसलिए मैं सिर्फ 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> 

विंडो कोड के पीछे इस

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

और विंडो xaml इस

0 की तरह

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> 

मैं जानता हूँ कि कार्यक्रम सही नहीं है और propably आसान बनाया जा सकता है, लेकिन जब एक तरह से समस्या को दिखाने के लिए पता लगाना यह है कि क्या मैं के साथ आया है। वैसे भी:

इसे प्रारंभ करें और यदि आप मेमोरी प्रोफाइलर हैं तो यह मेमोरी खपत की जांच करें, यह बहुत आसान हो जाता है। जोड़ें (टैब पर क्लिक करके इसे दिखाकर) और एक पृष्ठ हटाएं और आप देखेंगे कि सब कुछ ठीक काम करता है। कुछ भी रिसाव नहीं है। अब UserControl.Resources अनुभाग में ResourceDictionary के बजाय ResourceDictionary के बजाय का उपयोग साझा.एक्सएमएल शामिल करने के लिए करें। आप देखेंगे कि MyUserControl किसी पृष्ठ को हटाने के बाद स्मृति में रखा जाएगा, और इसमें MyUserControl होगा।

मुझे लगा कि XAML के माध्यम से कन्वर्टर्स, उपयोगकर्ता नियंत्रण इत्यादि के माध्यम से तत्काल यह सब कुछ होता है। आश्चर्यजनक रूप से यह कस्टम नियंत्रणों के साथ नहीं होगा। मेरा अनुमान है, क्योंकि कस्टम नियंत्रण, डेटा टेम्पलेट्स आदि पर कुछ भी वास्तव में तत्काल नहीं है।

तो पहले हम इससे कैसे बच सकते हैं? SharedResourceDictionary का उपयोग कर हमारे मामले में एक जरूरी है, लेकिन मेमोरी लीक इसे उत्पादक रूप से उपयोग करना असंभव बनाता है। लीक को UserControls के बजाय कस्टमकंट्रोल का उपयोग करके टाला जा सकता है, जो हमेशा व्यावहारिक रूप से नहीं होता है। तो UserControls को संसाधन संसाधन द्वारा संदर्भित क्यों मजबूत किया जाता है? मुझे आश्चर्य है कि किसी ने पहले ऐसा क्यों अनुभव नहीं किया, जैसा कि मैंने पुराने प्रश्न में कहा था, ऐसा लगता है कि हम संसाधन शब्दकोशों और एक्सएएमएल का बिल्कुल गलत इस्तेमाल करते हैं, अन्यथा मुझे आश्चर्य है कि वे इतने अक्षम क्यों हैं।

मुझे उम्मीद है कि कोई इस मामले पर कुछ प्रकाश डाल सकता है।

अग्रिम निको

+0

अपनी स्मृति प्रोफाइलर में, क्या वस्तु MyUserControl उदाहरण के संदर्भ में रखते हुए किया गया था? –

+0

मुझे निश्चित रूप से याद नहीं है, लेकिन मुझे लगभग निश्चित है कि यह एक संसाधन डिक्शनरी था, मेरे मामले में एक साझाResourceDictionary। – dowhilefor

उत्तर

5

धन्यवाद मैं काफी यकीन है कि अगर इससे आपकी समस्या का समाधान होगा नहीं हूँ। लेकिन मुझे ResourceDictionary संदर्भ नियंत्रण के साथ समान समस्याएं थीं और यह आलसी hydration के साथ करने के लिए थी। यहां पर post है। और यह कोड मेरी मुद्दों का समाधान:

public partial class App : Application 
{ 
    protected override void OnStartup(StartupEventArgs e) 
    { 
     WalkDictionary(this.Resources); 

     base.OnStartup(e); 
    } 

    private static void WalkDictionary(ResourceDictionary resources) 
    { 
     foreach (DictionaryEntry entry in resources) 
     { 
     } 

     foreach (ResourceDictionary rd in resources.MergedDictionaries) 
      WalkDictionary(rd); 
    } 
} 
+0

लिंक के लिए धन्यवाद जो कुछ अंतर्दृष्टि खोजने के लिए एक अच्छी शुरुआत है। यह पहले से ही मेरी मदद करता है। जबकि सभी संसाधनों को पूर्ववर्ती करके वास्तविक समाधान हमारे लिए बिल्कुल एक विकल्प नहीं है, क्योंकि हमारे पास कई संसाधन चुप हैं (कुछ टूटे हुए संसाधनों के साथ)। यदि कुछ भी बेहतर नहीं होता है तो मैं आपके उत्तर को सबसे अच्छे उत्तर के रूप में चिह्नित करूंगा। – dowhilefor

9

मैं एक बड़े ish WPF परियोजना में साझा संसाधन निर्देशिका की आवश्यकता होगी, के एक ही मुद्दे में चल रहा हूँ। स्रोत आलेख और टिप्पणियों को पढ़ते हुए, मैंने टिप्पणियों में सुझाए गए साझा डायरेक्ट्री क्लास में कुछ फ़िक्स शामिल किए हैं, जो कि मजबूत संदर्भ (_sourceUri में संग्रहीत) को हटा दिया गया है और डिज़ाइनर को सही तरीके से काम भी करता है। मैंने आपके उदाहरण का परीक्षण किया और यह काम करता है, डिजाइनर और मेमप्रोफाइलर दोनों ने सफलतापूर्वक कोई संदर्भ नहीं दिया। मुझे पता है कि अगर किसी को भी इसे आगे सुधार हुआ है अच्छा लगेगा, लेकिन यह क्या मैं अब के लिए साथ जा रहा हूँ है:

public class SharedResourceDictionary : ResourceDictionary 
{ 
    /// <summary> 
    /// Internal cache of loaded dictionaries 
    /// </summary> 
    public static Dictionary<Uri, ResourceDictionary> _sharedDictionaries = 
     new Dictionary<Uri, ResourceDictionary>(); 

    /// <summary> 
    /// Local member of the source uri 
    /// </summary> 
    private Uri _sourceUri; 

    /// <summary> 
    /// Gets or sets the uniform resource identifier (URI) to load resources from. 
    /// </summary> 
    public new Uri Source 
    { 
     get { 
      if (IsInDesignMode) 
       return base.Source; 
      return _sourceUri; 
     } 
     set 
     { 
      if (IsInDesignMode) 
      { 
       try 
       { 
        _sourceUri = new Uri(value.OriginalString); 
       } 
       catch 
       { 
        // do nothing? 
       } 

       return; 
      } 

      try 
      { 
       _sourceUri = new Uri(value.OriginalString); 
      } 
      catch 
      { 
       // do nothing? 
      } 

      if (!_sharedDictionaries.ContainsKey(value)) 
      { 
       // If the dictionary is not yet loaded, load it by setting 
       // the source of the base class 

       base.Source = value; 

       // add it to the cache 
       _sharedDictionaries.Add(value, this); 
      } 
      else 
      { 
       // If the dictionary is already loaded, get it from the cache 
       MergedDictionaries.Add(_sharedDictionaries[value]); 
      } 
     } 
    } 

    private static bool IsInDesignMode 
    { 
     get 
     { 
      return (bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, 
      typeof(DependencyObject)).Metadata.DefaultValue; 
     } 
    } 
} 
+3

इस दृष्टिकोण के लिए एक दिलचस्प विस्तार 'वीक रेफरेंस' का उपयोग करता है ताकि उपयोग में नहीं होने पर 'संसाधन डॉट्स' ऑब्जेक्ट कचरा एकत्र किया जा सके। विवरण के लिए [यह ब्लॉग पोस्ट] देखें (https://codeblitz.wordpress.com/2010/08/25/resourcedictionary-use-with-care/)। –

+0

ड्रू, क्या आपने कभी यह देखने के लिए परीक्षण किया था कि कचरा संग्रह काम करता है या नहीं? – tofutim

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^