2009-11-11 18 views
10

मेरे पास मेरे एप्लिकेशन में एक मेमोरी रिसाव मुद्दा है जो बड़ी मात्रा में छवियों को लोड करता है। मैं सी # के बजाय नया हूं, और सोचा कि मेमोरी रिसाव के मुद्दों के मेरे दिन पिछले थे। मैं समस्या का पता नहीं लगा सकता - शायद मैं कुछ अप्रबंधित मॉड्यूल का उपयोग कर रहा हूं जो मैं सही तरीके से संभाल नहीं पा रहा हूं?छवि लोडिंग मेमोरी लीक सी #

मेरी समस्या का वर्णन करने के लिए मैंने समस्या का कारण बनने के मूल को सरल बना दिया है और इसे एक स्वच्छ परियोजना में स्थानांतरित कर दिया है। ध्यान दें कि यह सब मूर्खतापूर्ण कोड है जो मूल एप्लिकेशन को प्रतिबिंबित नहीं करता है। परीक्षण आवेदन में मेरे पास दो बटन हैं, जो दो घटनाओं को ट्रिगर करते हैं।

बटन 1 - बनाएं: किसी ऑब्जेक्ट को डेटाकॉन्टेक्स्ट पर सेट करना। यह छवियों को लोड और उन्हें जीवित रखने DataContext करने के लिए वस्तु की स्थापना करके देगा:

var imgPath = @"C:\some_fixed_path\img.jpg"; 
DataContext = new SillyImageLoader(imgPath); 

बटन 2 - क्लीनअप: मेरी समझ है कि अगर मैं, SillyImageLoader जो फिर से छवियों रखती पकड़े संदर्भ का जाना तो जाने यह हटा दिया जाएगा। संदर्भ को छोड़ने के बाद मैं तुरंत स्मृति की मात्रा को देखने के लिए कचरा संग्रह को स्पष्ट रूप से ट्रिगर करता हूं।

DataContext = null; 
System.GC.Collect(); 

परीक्षण करते समय मैं 974 केबी जेपीईजी छवि लोड कर रहा हूं। इस के 30 बिटमैप प्रस्तुतियों को पकड़ने से मेरे आवेदन की स्मृति उपयोग ~ 18 एमबी से ~ 562 एमबी तक बढ़ जाती है। ठीक। लेकिन जब मैंने सफाई को मारा तो स्मृति केवल ~ 2 9 2 एमबी तक गिर गई। अगर मैं + क्लीनअप बनाएं दोहराता हूं तो मुझे एक और ~ 250 एमबी मेमोरी के साथ छोड़ दिया जाता है। तो जाहिर है कि कुछ अभी भी किसी के द्वारा आयोजित किया जाता है।

namespace MemoryLeakTest 
{ 
    using System; 
    using System.Drawing; 
    using System.Windows; 
    using System.Windows.Interop; 
    using System.Windows.Media.Imaging; 

    public class SillyImageLoader 
    { 
     private BitmapSource[] _images; 

     public SillyImageLoader(string path) 
     { 
      DummyLoad(path); 
     } 

     private void DummyLoad(string path) 
     { 
      const int numberOfCopies = 30; 
      _images = new BitmapSource[numberOfCopies]; 

      for (int i = 0; i < numberOfCopies; i++) 
      { 
       _images[i] = LoadImage(path); 
      } 
     } 

     private static BitmapSource LoadImage(string path) 
     { 
      using (var bmp = new Bitmap(path)) 
      { 
       return Imaging.CreateBitmapSourceFromHBitmap(
        bmp.GetHbitmap(), 
        IntPtr.Zero, 
        Int32Rect.Empty, 
        BitmapSizeOptions.FromEmptyOptions()); 
      }    
     } 
    } 
} 

कोई भी विचार:

यहाँ SillyImageLoader-कोड है? समस्या बिटमैप स्रोत के साथ प्रतीत होती है। केवल बिटमैप को पकड़ना कोई स्मृति रिसाव नहीं है। मैं बिटमैप स्रोत का उपयोग कर रहा हूं ताकि इसे किसी छवि की स्रोत प्रॉपर्टी पर सेट किया जा सके। क्या मुझे यह अलग करना चाहिए? यदि ऐसा है - मैं अभी भी स्मृति रिसाव का जवाब जानना चाहता हूं।

धन्यवाद।

+0

लोड इमेज से लौट आए बिटमैप स्रोत पर निपटान कौन कर रहा है? –

+0

मैंने सोचा, वास्तव में इसके आधार पर एक उत्तर पोस्ट किया है लेकिन मुझे बिटमैप स्रोत पर एक निपटान नहीं दिखाई दे रहा है (मैंने जवाब हटा दिया है) –

+0

आप अपने ऐप के मेमोरी उपयोग की निगरानी कैसे कर रहे हैं? कार्य प्रबंधक? –

उत्तर

13

जब आप

bmp.GetHbitmap() 

फोन बिटमैप की एक प्रति बनाई गई है। आपको उस ऑब्जेक्ट पर पॉइंटर का संदर्भ रखना होगा और

DeleteObject(...) 

पर कॉल करना होगा।

here से

:

टिप्पणियां

आप GDI बिटमैप वस्तु के द्वारा प्रयोग किया स्मृति को मुक्त करने के GDI DeleteObject विधि फोन करने के लिए जिम्मेदार हैं।


आप अपने आप को BitmapSource के बजाय BitmapImage का उपयोग करके बिटमैप कॉपी करने का सिरदर्द (और भूमि के ऊपर) को बचाने के लिए सक्षम हो सकता है। यह आपको एक चरण में लोड और बनाने की अनुमति देता है।

+0

यह बिल्कुल सही है और स्मृति मुद्दों को दूर कर दिया गया है! धन्यवाद! और इसी तरह के उत्तरों वाले अन्य लोगों के लिए thx! आप सही हैं कि मैं इस विशेष उदाहरण में बिटमैप छवि का उपयोग कर सकता हूं। हालांकि, मेरे वास्तविक अनुप्रयोग में मेरे पास एक छवि फ़ाइल का पथ नहीं है, लेकिन किसी तृतीय पक्ष लाइब्रेरी के किसी अन्य ऑब्जेक्ट से बिटमैप्स प्राप्त करें। इस बारे में मैं वास्तव में इतना कुछ नहीं कर सकता। तो मैं उरी का उपयोग नहीं कर सकता - मुझे बिटमैप का उपयोग करने की ज़रूरत है .. – stiank81

7

आपको पर GDI DeleteObject विधि को GetHBitmap() से लौटाए गए पॉइंटर को कॉल करने की आवश्यकता है। विधि से लौटा IntPtr स्मृति में ऑब्जेक्ट की प्रतिलिपि के लिए एक सूचक है।यह मैन्युअल रूप से निम्नलिखित कोड का उपयोग कर मुक्त कर दिया जाना चाहिए:

[System.Runtime.InteropServices.DllImport("gdi32.dll")] 
public static extern bool DeleteObject(IntPtr hObject); 

private static BitmapSource LoadImage(string path) 
{ 

    BitmapSource source; 
    using (var bmp = new Bitmap(path)) 
    { 

     IntPtr hbmp = bmp.GetHbitmap(); 
     source = Imaging.CreateBitmapSourceFromHBitmap(
      hbmp, 
      IntPtr.Zero, 
      Int32Rect.Empty, 
      BitmapSizeOptions.FromEmptyOptions()); 

     DeleteObject(hbmp); 

    } 

    return source; 
} 
5

ऐसा लगता है कि जब आप GetHBitmap() फोन आप वस्तु

[System.Runtime.InteropServices.DllImport("gdi32.dll")] 
public static extern bool DeleteObject(IntPtr hObject); 

private void DoGetHbitmap() 
{ 
    Bitmap bm = new Bitmap("Image.jpg"); 
    IntPtr hBitmap = bm.GetHbitmap(); 

    DeleteObject(hBitmap); 
} 

मेरा अनुमान है कि कि BitmapSource नहीं है मुक्त कराने के लिए जिम्मेदार हैं इस वस्तु को मुक्त करने की जिम्मेदारी लें।

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