2013-03-25 3 views
7

मैं निम्नलिखित कोड है, जो एक OutOfMemoryException उत्पन्न होगा चला जब:कचरा कोलेक्टर का विकल्प क्या है?

public partial class MainWindow : Window 
{ 
    private DrawingVisual myVisual = new DrawingVisual(); 

    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     myVisual = GetVisual(); 
     graphicsCanvas.AddVisual(myVisual); 
    } 

    private void Graphics_Canvas_MouseMove(object sender, MouseEventArgs e) 
    { 
     //get the data visual: 
     DrawingVisual tempVisual = GetVisual(); 

     //first clear the current display data: 
     graphicsCanvas.RemoveVisual(myVisual); 

     //get the data visual: 
     myVisual = tempVisual; 

     graphicsCanvas.AddVisual(myVisual); 

     //GC.Collect(); 
    } 

    private DrawingVisual GetVisual() 
    { 
     double width = graphicsCanvas.ActualWidth; 
     double height = graphicsCanvas.ActualHeight; 

     DrawingVisual dV = new DrawingVisual(); 

     Rect clipRect = new Rect(0, 0, width, height); 

     dV.Clip = new RectangleGeometry(clipRect); 

     using (DrawingContext dC = dV.RenderOpen()) 
     { 
      RenderTargetBitmap rTB = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32); 

      if (rTB.CanFreeze) 
      { 
       rTB.Freeze(); 
      } 

      dC.DrawImage(rTB, clipRect); 
     } 

     return dV; 
    } 
} 

जहां एक Graphics_Canvas के रूप में परिभाषित किया गया है इस प्रकार है:

class Graphics_Canvas : Canvas 
{ 
    private List<DrawingVisual> visuals = new List<DrawingVisual>(); 

    protected override int VisualChildrenCount 
    { 
     get { return visuals.Count; } 
    } 

    protected override Visual GetVisualChild(int index) 
    { 
     return visuals[index]; 
    } 

    public void AddVisual(DrawingVisual visual) 
    { 
     visuals.Add(visual); 

     base.AddVisualChild(visual); 
     base.AddLogicalChild(visual); 
    } 

    public bool ContainsVisual(DrawingVisual visual) 
    { 
     return visuals.Contains(visual); 
    } 

    public bool HasVisuals 
    { 
     get { return visuals.Count > 0; } 
    } 

    public void RemoveAllVisuals() 
    { 
     for (int i = 0; i < visuals.Count; i++) 
     { 
      RemoveFromLogicalTree(visuals[i]); 
     } 

     visuals.Clear(); 
    } 

    private void RemoveFromLogicalTree(Visual visual) 
    { 
     RemoveLogicalChild(visual); 
     RemoveVisualChild(visual); 
    } 

    public void RemoveLastVisual() 
    { 
     if (visuals.Count > 0) 
     { 
      int index = visuals.Count - 1; 

      RemoveFromLogicalTree(visuals[index]); 
      visuals.Remove(visuals[index]); 
     }  
    } 

    public void RemoveVisual(DrawingVisual visual) 
    { 
     RemoveFromLogicalTree(visual); 
     visuals.Remove(visual);    
    } 
} 

और XAML Window बनाने के लिए इस तरह है:

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:csMemoryLeakTestProject" x:Class="csMemoryLeakTestProject.MainWindow" 
    Title="MainWindow" 
    Background="Gray" 
    Height="600" Width="800" 
    WindowStartupLocation="CenterScreen" 
    Loaded="Window_Loaded"> 
    <Grid> 
     <local:Graphics_Canvas Margin="12" Background="White" x:Name="graphicsCanvas" MouseMove="Graphics_Canvas_MouseMove"/> 
    </Grid> 
</Window> 

अब, यह मेरे बिंदु को स्पष्ट करने के लिए सिर्फ एक उदाहरण है, जो कि मुझे समझ में नहीं आता है विकल्प पर कचरा कलेक्टर का उपयोग करने के लिए यहां है ...

यदि आप प्रोग्राम चलाते हैं, और माउस को Graphics_Canvas पर ले जाते रहें, तो स्मृति उपयोग तब तक बनाता है जब तक आपको OutOfMemoryException प्राप्त नहीं होता है। यदि आप GC.Collect() में जोड़ते हैं जहां मैंने इसे टिप्पणी की है, तो ऐसा नहीं होता है (हालांकि स्मृति मेरे द्वारा कारणों से, और मेरी समस्या से जुड़ी उम्मीदों के लिए, एक छोटी राशि से बढ़ती है), और कार्यक्रम कार्य करना जारी रखता है।

तो, GC क्यों नहीं चलता है और इस मेमोरी को साफ़ करता है और अपवाद को रोकता है? अगर मैं कुछ बहुत ही मौलिक त्रुटि कर रहा हूं तो मैं किसी के लिए इसे इंगित करने के लिए बहुत खुश हूं ताकि मैं इससे आगे बढ़ सकूं।

मैंने इस वेबसाइट पर कई बार देखा है और अन्य प्रोग्रामर से सलाह देते हैं कि "कचरा कलेक्टर का कभी भी उपयोग न करें"। मैं सर्वोत्तम अभ्यास के अनुरूप होना चाहता हूं, लेकिन मुझे इस तरह की स्थितियों में नहीं दिख रहा है और मैं क्या कर सकता हूं।

उत्तर

9

यह GC की कोई गलती नहीं है कि प्रोग्राम अधिक मेमोरी प्रबंधित करने में सक्षम नहीं है। अपने कार्यक्रम में आप कार्य करें:

private void Graphics_Canvas_MouseMove(object sender, MouseEventArgs e) 
{ 
    .... 
    //ADD ELEMENTS ON EVERY MOVE ! 
    graphicsCanvas.AddVisual(myVisual); 

    //GC.Collect(); 
} 

नीति अध्ययन माउस की प्रत्येक गतिविधि के लिए एक तत्व जोड़ है, तो वृद्धि संग्रह आकार। आप क्या उम्मीद करेंगे?

तो, 90% में मामलों, समस्याओं के इन प्रकार के लिए समाधान, rearchitect अपने कोड है।

उदाहरण:

यह शायद ही संभव है कि आप MouseMove पर की जरूरत है दृश्य की एक chidren संग्रह करने के लिए हर बार एक नई तत्व जोड़ है। हो सकता है कि यह पहले से मौजूद एक का पुन: उपयोग करने का मामला हो।

GC का उपयोग का उपयोग सुझाया गया है, लेकिन कभी-कभी हमें इसका उपयोग करने की आवश्यकता होती है। लेकिन, मैं दोहराता हूं, मैं शायद ही विश्वास कर सकता हूं कि में यह मामला आपको इस तरह से प्रोग्राम प्रबंधित करने की आवश्यकता है।

+2

पूरी तरह ईमानदार होने के लिए; मुझे यह अजीब लगता है कि सिस्टम 'जीसी.कोलेक्ट() 'का प्रयास करने से पहले' आउटऑफमेमरी अपवाद '** को फेंक देगा। केवल मेरे दो सेंट्स। – Nolonar

+3

प्रतीक्षा करें, कोड पहले * तत्व को हटा रहा है और फिर एक और जोड़ रहा है। कोई बात नहीं। –

+1

'वर्तमान प्रदर्शन डेटा को पहले स्पष्ट करें' भाग के बारे में क्या? – RichieHindle

-1

मुझे लगता है कि यह बताता है कि आपकी वस्तुओं को जीवित रखने में क्या हो सकता है;

http://msdn.microsoft.com/en-us/library/bb613565.aspx

संक्षेप में, ईवेंट हैंडलर में संदर्भ अभी भी मौजूद हो सकते हैं।

+1

यदि समस्या थी, तो 'GC.Collect()' को कॉल करना इसे ठीक नहीं करेगा। – RichieHindle

+0

@IvoTops हां, मैंने इसके बारे में पढ़ा है। हालांकि ऊपर दिए गए कोड इस कार्यक्रम के लिए संपूर्ण कोड है, और मैंने कोई कार्यक्रम नहीं जोड़ा है, इसलिए मुझे यकीन नहीं है कि यह कारण हो सकता है। यदि कैनवास दृश्यों के पीछे खुद को जोड़ता है, तो मैं उन्हें हटाने के लिए और क्या कर सकता हूं? – Greg

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