2010-11-11 13 views
16

मैं वर्तमान में एक विधि को डीबग कर रहा हूं जिसका उपयोग हम अपने सिस्टम में प्रदर्शित करने से पहले एक निश्चित पाठ के साथ छवियों को टैग करने के लिए करते हैं।GC.AddMemoryPressure() के साथ OutOfMemoryException को रोकना?

टैग तरीके पल में इस तरह दिखता है:

private static Image TagAsProductImage(Image image) 
{ 
    try 
    { 
     // Prepares the garbage collector for added memory pressure (500000 bytes is roughly 485 kilobytes). 
     // Should solve some OutOfMemoryExceptions. 
     GC.AddMemoryPressure(500000); 

     using (Graphics graphics = Graphics.FromImage(image)) 
     { 
      // Create font. 
      Font drawFont = new Font("Tahoma", image.Width*IMAGE_TAG_SIZE_FACTOR); 

      // Create brush. 
      SolidBrush drawBrush = new SolidBrush(Color.Black); 

      // Create rectangle for drawing. 
      RectangleF drawRect = new RectangleF(0, image.Height - drawFont.GetHeight(), image.Width, 
                drawFont.GetHeight()); 

      // Set format of string to be right-aligned. 
      StringFormat drawFormat = new StringFormat(); 
      drawFormat.Alignment = StringAlignment.Far; 

      // Draw string to screen. 
      graphics.DrawString(TAG_TEXT, drawFont, drawBrush, drawRect, drawFormat); 
     } 
    } 
    // If an out of memory exception is thrown, return the unaltered image. 
    catch(OutOfMemoryException) 
    { 
     GC.RemoveMemoryPressure(500000); 
     return image; 
    } 

    GC.RemoveMemoryPressure(500000); 
    return image; 
} 

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

हमें OutOfMemoryExceptions के साथ using (Graphics... तक पहुंचने में समस्याएं आ रही हैं (जब टैगिंग से पहले सर्वर से छवि को पुनर्प्राप्त करने की आवश्यकता होती है, यदि छवि कैश में मौजूद है तो टैगिंग कोई समस्या नहीं है)।

आउटऑफमेमरी अपवाद को रोकने/रोकने के लिए मैंने तीन अलग-अलग दृष्टिकोणों की कोशिश की है, और जब वे काम करते हैं तो मुझे वास्तव में उनमें से कोई भी पसंद नहीं है।

सबसे पहले मैंने Graphics.FromImage(image) पर कॉल करने से पहले एक सामान्य GC.Collect(); करने का प्रयास किया जो (निश्चित रूप से) काम करता है लेकिन मुझे संग्रह पर मजबूर होना पसंद नहीं है क्योंकि यह प्रदर्शन पर एक बड़ी हिट छोड़ देता है।

मेरा दूसरा दृष्टिकोण कैच-स्टेटमेंट में GC.Collect() पर कॉल करना था और फिर TagAsProductImage(image) को फिर से कॉल करना था, लेकिन यदि जीसी पर्याप्त स्मृति को मुक्त करने में विफल रहता है तो यह अनंत लूप का कारण बन सकता है।

और अंततः मैं उपरोक्त कोड के साथ समाप्त हुआ, जिसे मैं नहीं कह सकता कि मैं या तो शौकीन हूं।

मैं शायद सेवा से छवि प्राप्त करने के पूरे ऑपरेशन के बाद GC.Collect() का उपयोग कर दूर हो सकता हूं -> बचत -> टैगिंग काफी बड़ा है इसलिए संग्रह से प्रदर्शन प्रदर्शन न्यूनतम होगा लेकिन मुझे वाकई पसंद आएगा एक बेहतर समाधान।

यदि किसी के पास इसका कोई स्मार्ट समाधान है, तो कृपया साझा करें।

उत्तर

16

यदि आप यह सुनिश्चित करने के लिए एक तरीका ढूंढ रहे हैं कि आपके पास ऑपरेशन के लिए पर्याप्त मेमोरी उपलब्ध है, तो MemoryFailPoint का उपयोग करें।

इसके साथ, using के माध्यम से, आप एक ऐसे क्षेत्र को परिभाषित कर सकते हैं जिसमें आपको कुछ निश्चित स्मृति की आवश्यकता होगी। यदि यह उपलब्ध नहीं है, तो यह एक पुनर्प्राप्त करने योग्य InsufficientMemoryException फेंक देगा।

अधिक जानकारी के लिए http://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint.aspx देखें।

+0

मुझे मेमोरीफेलपॉइंट के बारे में पता नहीं था, इसलिए सिर के लिए धन्यवाद, यह सीधे मेरे "उपयोगी कोड को याद रखने के लिए" कोने पर जा रहा है। दुर्भाग्य से यह मदद नहीं की, मैंने 1 से 200 एमबी से सबकुछ आवंटित करने का प्रयास किया, यह सभी मामलों में सफल रहा लेकिन ग्राफिक्स ऑब्जेक्ट बनाने की कोशिश करते समय अभी भी आउटऑफमेमरी अपवाद फेंक दिया। देखना जारी रखना होगा (जीडीआई + और मेमोरी हैंडलिंग कभी-कभी दर्द हो सकती है)। – Mantisen

+0

मैं इसे लेता हूं यह विफल रहता है यह हमेशा असफल नहीं होता ??? उपयोग करने से पहले आपको क्या करना चाहिए, 'जीसी.गेटटॉटल मेमरी (झूठी)' और उपयोग ब्लॉक के अंत से पहले, एक और करें। अंतर उस प्रक्रिया के लिए उपयोग की जाने वाली स्मृति की वास्तविक मात्रा होनी चाहिए। यदि 'MemoryFailPoint' को वह राशि प्रदान नहीं करती है, तो ठीक है, मैं विचारों से बाहर हूं: पी। –

+0

आप बिल्कुल सही हैं, यह केवल तब विफल हो जाता है जब छवि कैश में पहले नहीं थी लेकिन इस विधि को कॉल करने से ठीक पहले हमारे छवि सर्वर से पुनर्प्राप्त किया गया था। अजीब चीज यह है कि 'मेमोरीफेलपॉइंट' मेमोरी आवंटित करने का प्रबंधन करता है (हर बार!) लेकिन 'ग्राफिक्स ...' का उपयोग करके आउटऑफमेमरी एक्सेप्शन फेंकता है वैसे भी अगर छवि पहले कैश-फ़ोल्डर में नहीं थी। – Mantisen

10

आप यहाँ एक अलग समस्या है, यह कोड बहुत छोटी स्मृति का उपयोग करता है। अफसोस की बात है कि जीडीआई + अपवाद बहुत खराब हैं। TaskMgr.exe, प्रक्रिया टैब के साथ इसका निदान करें। देखें + कॉलम का चयन करें और जीडीआई ऑब्जेक्ट्स, हैंडल और यूजर ऑब्जेक्ट्स पर टिकटें।

यदि मेरा संदेह सही है, तो आप इस कोड के चलते लगातार अपनी प्रक्रिया के लिए जीडीआई ऑब्जेक्ट काउंटर देखेंगे। जब यह 10,000 विंडोज तक पहुंचता है तो यह तय करता है कि कोड के साथ कुछ मौलिक रूप से गलत है और कोई और हैंडल बनाने से इंकार कर देता है। जीडीआई + इसके बारे में थोड़ा गड़बड़ हो जाता है और स्मृति त्रुटि से बाहर रिपोर्ट करता है। गलत, यह 'हैंडल नहीं बना सका' त्रुटि होनी चाहिए थी। एक त्रुटि कोड जो उसके पास नहीं है। अपवाद में सुधार करने के लिए .NET शक्तिहीन है।

Anyhoo, कारण यह है कि आप फ़ॉन्ट और ब्रश पर निपटान() को कॉल नहीं कर रहे हैं।उन्हें के साथ कथन का उपयोग करके लपेटें। यह आम तौर पर परेशानी का कारण नहीं बनता है लेकिन आपका प्रोग्राम स्पष्ट रूप से फाइनलज़र थ्रेड को लात मारने के लिए बहुत कम कचरा एकत्रित स्मृति का उपयोग कर रहा है।

+0

मैंने जो कोड शामिल किया है वह अन्यथा काफी बड़ी कक्षा में एक छोटी सी विधि है (जिस संदर्भ में विधि को संदर्भित किया जा रहा है उसका वर्णन देखें) और वह वर्ग बदले में कई उपयोगकर्ताओं के साथ एक बहुत ही डेटा भारी प्रणाली का हिस्सा है। मैंने ब्रश या फ़ॉन्ट का उपयोग करने से पहले अपवाद को फेंक दिया है, क्योंकि इस ब्रश या फ़ॉन्ट का उपयोग करने से पहले अपवाद को फेंक दिया गया है, क्योंकि इस विशिष्ट विधि (पेर्फॉन, टास्कमैनगर इत्यादि का उपयोग करके) में इस विशिष्ट त्रुटि को आउटऑफमेमरी अपवाद में ढूंढने में कामयाब रहा है और चूंकि मेरे पास उन्हें उपयोग के अंदर उपयोग किया गया है ग्राफिक्स ऑब्जेक्ट होने पर ग्राफिक्स को उनका निपटान किया जाना चाहिए। क्या वे नहीं चाहिए? लेकिन मैं सहमत हूं कि जीडीआई + अपवाद क्रमी हैं। – Mantisen

+2

नहीं, ग्राफिक्स स्वचालित रूप से कुछ भी निपटान नहीं करता है। –

+0

'उपयोग' कथन में डालने पर भी नहीं? मैंने हमेशा सोचा है कि उपयोग करने वाले दायरे से बाहर निकलने पर किसी भी कथन में डाल दिया गया था। – Mantisen