2010-03-29 4 views
10

अपडेट करें: मैंने इसे एक और अधिक स्वच्छ रूप से स्थापित, मशीन पर करने की कोशिश की। मैं उस मशीन पर इसे पुन: पेश नहीं कर सका। अगर मुझे पता चलता है कि क्या अपमानजनक (VSStudio) घटक इसका कारण बनता है, तो मैं आपको बता दूंगा।डब्ल्यूपीएफ में: बच्चे। रिमूव या बच्चे। क्लीयर ऑब्जेक्ट्स मुक्त नहीं करता

मैं कोड से कुछ UIElements बना रहा हूं और सामान साफ़ करने के लिए कचरा संग्रह की उम्मीद कर रहा था। हालांकि, जब मैं इसकी अपेक्षा करता था तब ऑब्जेक्ट फ्री-एड नहीं होते थे। मैं उन्हें RemoveAt (0) पर मुक्त होने की उम्मीद कर रहा था, लेकिन वे केवल कार्यक्रम के अंत में मुक्त हो गए हैं।

कैनवास के बच्चों के संग्रह से हटाए जाने पर वस्तुओं को मुक्त कैसे किया जा सकता है?

<Window x:Class="WpfApplication1.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Title="Window1" Height="300" Width="300" 
    MouseDown="Window_MouseDown"> 
    <Grid> 
    <Canvas x:Name="main" /> 
    </Grid> 
</Window> 

कोड के पीछे है:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
    InitializeComponent(); 
    } 

private void Window_MouseDown(object sender, MouseButtonEventArgs e) 
{ 
    GC.Collect(); // This should pick up the control removed at a previous MouseDown 
    GC.WaitForPendingFinalizers(); // Doesn't help either 

    if (main.Children.Count == 0) 
    main.Children.Add(new MyControl() { Background = Brushes.Yellow, Width = 100, Height = 50 }); 
    else 
    main.Children.RemoveAt(0); 
} 
} 

public class MyControl : UserControl 
{ 
    ~MyControl() 
    { 
    Debug.WriteLine("Goodbye"); 
    } 
} 

उत्तर

3

सी # में वस्तुओं स्वचालित रूप से "मुक्त कर दिया" जैसे ही वे अब नहीं किया जाता नहीं हैं।

इसके बजाय, जब आप अपने नियंत्रण से ऑब्जेक्ट को हटाते हैं, तो उस बिंदु पर कचरा संग्रह के लिए योग्य हो जाता है, मानते हैं कि आपके पास उस UIelement के लिए कोई अन्य संदर्भ नहीं है।

एक बार ऑब्जेक्ट "अनियंत्रित" हो जाता है (आपके आवेदन में किसी भी प्रयुक्त ऑब्जेक्ट से प्रत्यक्ष या परोक्ष रूप से कोई संदर्भ नहीं है), यह संग्रह के लिए योग्य हो जाता है। कचरा कलेक्टर तब अंततः, आपकी वस्तु को साफ करेगा, लेकिन जब ऐसा होता है तो आप कुछ (आमतौर पर) नियंत्रण नहीं करते हैं।

बस विश्वास करें कि यह अंततः साफ हो जाएगा। यह सी # (और सामान्य रूप से .NET) की सुंदरता है - प्रबंधन, और चिंता, इसका आपके लिए संभाला जाता है।


संपादित करें: कुछ परीक्षणों के बाद, ऐसा लगता है कि विंडो अगले लेआउट पास तक UIelement का संदर्भ रखती है। कैनवास बच्चे से तत्व (रों) को हटाने के बाद

this.UpdateLayout(); 

: आप के लिए एक कॉल जोड़कर होने के लिये यह मजबूर कर सकते हैं। यह वस्तुओं को जीसी के लिए उपलब्ध कराने का कारण बन जाएगा।

+0

मुझे पता है का उपयोग कर अपंजीकृत कर, लेकिन इस मामले में ऐसा नहीं लगता। जब मैं माउसडाउन हैंडलर की शुरुआत में जीसी। कोलेक्ट() जोड़ता हूं, तो उसे कचरा संग्रह के लिए योग्य नियंत्रण लेना चाहिए। यह नहीं है मैं वहां इकट्ठा होता हूं अभी भी कैनवास ऑब्जेक्ट में आंतरिक रूप से इसका कुछ संदर्भ होना चाहिए। –

+0

@ बार्ट: हैंडलर के अंत में जीसी.कोलेक्शन जोड़ने का प्रयास करें - हैंडलर की शुरुआत में नियंत्रण यूआई में अभी भी है ... क्या इससे मदद मिलती है? –

+0

@ बार्ट: इसके अलावा - GC.WaitForPendingFinalizers() को कॉल जोड़ने का प्रयास करें - देखें: http://msdn.microsoft.com/en-us/library/system.gc.waitforpendingfinalizers.aspx –

8

बदलें

public class MyControl : UserControl

public class MyControl : ContentControl

के लिए और इसे कहेंगे अलविदा (दूसरी बार के बाद आप नियंत्रण को हटा दें।) मैं भी का उपयोग करके सत्यापित स्मृति लीक नहीं करता है

Debug.WriteLine("mem: " + GC.GetTotalMemory(true).ToString());

इसके अलावा, this देखें:

आप grid.Children साफ़ करके testControl निकालने के लिए, लेकिन यह तुरंत कचरा संग्रहण के योग्य नहीं है। इस पर कई एसिंक्रोनस ऑपरेशंस लंबित हैं, और जब तक उन परिचालनों को पूरा नहीं किया जाता है तब तक यह GC'd नहीं हो सकता है (इनमें अनलोडेड ईवेंट और प्रतिपादन इंजन में कुछ क्लीनअप कोड शामिल हैं)।

मैंने सत्यापित किया कि यदि आप इन परिचालनों को पूरा करने तक प्रतीक्षा करते हैं (ContextIdle प्राथमिकता पर डिस्पैचर ऑपरेशन शेड्यूल करके कहें), टेस्टकंट्रोल टेक्स्टब्लॉक पर बाइंडिंग की उपस्थिति से स्वतंत्र, जीसी के लिए योग्य हो जाता है।

उपयोगकर्ता नियंत्रण में या तो एक आंतरिक घटना होनी चाहिए जो जल्दी से साफ नहीं हो पाती है, या यह वीएस -2010 आरसी के साथ एक बग हो सकती है। मैं कनेक्ट के माध्यम से इसकी रिपोर्ट करूंगा, लेकिन अब ContentControl पर स्विच करें।

चूंकि आप UserControl का उपयोग कर रहे हैं, मुझे लगता है कि आपको जेनेरिक.एक्सएएमएल टेम्पलेट का उपयोग करने के लिए भी स्विच करना होगा। यह बदलाव के लिए बहुत मुश्किल नहीं है (और अधिकांश चीजों के लिए एक बेहतर समाधान है।)

3

सी # में कचरा संग्रह की 3 पीढ़ियां हैं, इसलिए यदि आपकी वस्तुओं का कोई संदर्भ नहीं है, तो यह भी ले सकता है उन्हें मुक्त करने के लिए 3 कचरा संग्रह।

आप एक 3 पीढ़ी कचरा संग्रहण के लिए मजबूर करने पैरामीटर GC.Collect() का उपयोग कर सकते हैं,
हालांकि, सबसे अच्छा approuch GC.Collect (फोन नहीं करने के लिए) अपने आप को है,
बजाय IDisposable इंटरफ़ेस का उपयोग और बच्चों को एक अवलोकन करने योग्य चयन पर बाध्य करें और जब आप किसी भी हटाए गए ऑब्जेक्ट्स का संग्रह चेंज इवेंट डिस्प्ले() प्राप्त करते हैं।

0

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

2

आपको यह रुचि मिल सकती है। मुझे हाल ही में पता चला है कि एक्स: नाम मार्कअप एक्सटेंशन स्ट्रिंग नाम द्वारा कुंजीपटल शब्दकोश में अभिभावक नियंत्रण में UIElement का संदर्भ संग्रहीत करता है।

जब आप अपने माता-पिता से UIElement को हटाते हैं, तो शब्दकोश नियंत्रण का संदर्भ रखता है।

एक ब्लॉग पोस्ट/वीडियो यहाँ स्मृति रिसाव डिबगिंग नहीं है: WPF x:Name Memory Leak

समाधान का उपयोग नहीं करने के लिए एक्स है: नाम या यह सुनिश्चित करें कि नियंत्रण है कि एक्स द्वारा जीवित रखा जाता है: नाम साफ़ होते ताकि दृश्य पेड़ के एक हिस्से को एकत्र करने से पहले बहुत अधिक स्मृति का उपभोग न किया जाए।

अद्यतन: आप एक नामित वर्ग NameScope

this.grid.Children.Remove(child); // Remove the child from visual tree 
NameScope.GetNameScope(this).UnregisterName("child"); // remove the keyed name 
this.child = null; // null the field 

// Finally it is free to be collected! 
संबंधित मुद्दे