2013-02-09 37 views
7

मैं एक वेबब्रोसर नियंत्रण के साथ एमएसएचटीएमएल का उपयोग कर रहा हूं क्योंकि यह मुझे उन चीज़ों तक पहुंच प्रदान करता है जो WebBrowser टेक्स्ट नोड्स जैसे नहीं हैं। मैंने यहां और वेब पर कई पोस्ट देखी हैं जहां लोग कहते हैं कि आपको संदर्भित प्रत्येक COM ऑब्जेक्ट के लिए ReleaseComObject पर कॉल करना होगा। तो, कहते हैं कि मैं यह कर:क्या मुझे हर एमएसएचटीएमएल ऑब्जेक्ट पर रिलीजकॉम ऑब्जेक्ट को कॉल करने की ज़रूरत है?

var doc = myBrowser.Document.DomDocument as IHTMLDocument2;

मैं doc जारी करने के लिए की जरूरत है? कैसे body इस कोड में:

var body = (myBrowser.Document.DomDocument as IHTMLDocument2).body;

इन वस्तुओं के रूप में जल्द ही एक RCW है कि उन्हें जारी होगा द्वारा लिपटे के रूप में वहाँ उन्हें कोई और अधिक संदर्भ हैं नहीं कर रहे हैं? यदि नहीं, तो क्या उनमें से प्रत्येक के लिए फाइनलर (निपटान का उपयोग करने के बजाए) के लिए एक रैपर बनाने का अच्छा विचार होगा, जैसे ही कचरा कलेक्टर किक करता है (जैसे कि मुझे मैन्युअल रूप से चिंता करने की आवश्यकता नहीं है उन्हें निपटाना)?

बात यह है कि, मेरे आवेदन में स्मृति रिसाव है और मेरा मानना ​​है कि इससे संबंधित है। एएनटीएस मेमोरी प्रोफाइलर के अनुसार, कार्यों में से एक (एमएसएचटीएमएल ऑब्जेक्ट्स का उपयोग करने वाले कई अन्य लोगों में) जो Microsoft.CSharp.RuntimeBinder.Semantics.LocalVariableSymbol ऑब्जेक्ट्स के समूह के संदर्भ में हैं जो जेनरेशन 2 में मेमोरी का उपयोग कर ऑब्जेक्ट्स की शीर्ष सूची में हैं, यह एक है:

internal static string GetAttribute(this IHTMLDOMNode element, string name) 
{ 
    var attribute = element.IsHTMLElement() ? ((IHTMLElement)element).getAttribute(name) : null; 
    if (attribute != null) return attribute.ToString(); 
    return ""; 
} 

यह सुनिश्चित नहीं है कि attribute के बाद से क्या गलत है, केवल एक स्ट्रिंग है।

यहाँ एक और समारोह है कि चींटियों प्रोफाइलर के उदाहरण रिटेंशन ग्राफ पर दिखाया जाता है (मैं FinalReleaseComObject रों का एक समूह जोड़ा है, लेकिन अभी भी दिखाया गया है):

private void InjectFunction(IHTMLDocument2 document) 
{ 
    if (null == Document) throw new Exception("Cannot access current document's HTML or document is not an HTML."); 

    try 
    { 
     IHTMLDocument3 doc3 = document as IHTMLDocument3; 
     IHTMLElementCollection collection = doc3.getElementsByTagName("head"); 
     IHTMLDOMNode head = collection.item(0); 
     IHTMLElement scriptElement = document.createElement("script"); 
     IHTMLScriptElement script = (IHTMLScriptElement)scriptElement; 
     IHTMLDOMNode scriptNode = (IHTMLDOMNode)scriptElement; 
     script.text = CurrentFuncs; 
     head.AppendChild(scriptNode); 
     if (Document.InvokeScript(CurrentTestFuncName) == null) throw new Exception("Cannot inject Javascript code right now."); 
     Marshal.FinalReleaseComObject(scriptNode); 
     Marshal.FinalReleaseComObject(script); 
     Marshal.FinalReleaseComObject(scriptElement); 
     Marshal.FinalReleaseComObject(head); 
     Marshal.FinalReleaseComObject(collection); 
     //Marshal.FinalReleaseComObject(doc3); 
    } 
    catch (Exception ex) 
    { 
     throw ex; 
    } 
} 

मैं ReleaseComObject जोड़ा है, लेकिन अभी भी समारोह हो रहा है कुछ के लिए संदर्भ आयोजित करना। इसलिए मुझे लगता है सब कुछ ठीक से जारी की गई है

private void InjectFunction(IHTMLDocument2 document) 
{ 
    if (null == Document) throw new Exception("Cannot access current document's HTML or document is not an HTML."); 

    try 
    { 
     IHTMLDocument3 doc3 = document as IHTMLDocument3; 
     IHTMLElementCollection collection = doc3.getElementsByTagName("head"); 
     IHTMLDOMNode head = collection.item(0); 
     IHTMLElement scriptElement = document.createElement("script"); 
     IHTMLScriptElement script = (IHTMLScriptElement)scriptElement; 
     IHTMLDOMNode scriptNode = (IHTMLDOMNode)scriptElement; 
     script.text = CurrentFuncs; 
     head.AppendChild(scriptNode); 
     if (Document.InvokeScript(CurrentTestFuncName) == null) throw new Exception("Cannot inject Javascript code right now."); 
     Marshal.FinalReleaseComObject(scriptNode); 
     Marshal.FinalReleaseComObject(script); 
     Marshal.FinalReleaseComObject(scriptElement); 
     Marshal.FinalReleaseComObject(head); 
     Marshal.FinalReleaseComObject(collection); 
     Marshal.ReleaseComObject(doc3); 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show("Couldn't release!"); 
     throw ex; 
    } 
} 

MessageBox.Show("Couldn't release!"); लाइन कभी नहीं मारा जाता है: यहाँ कैसे मेरे समारोह अब की तरह लग रहा है। यहां बताया गया है चींटियों से पता चलता है:

ANTS memory profiler screenshot

मुझे पता नहीं क्या है कि साइट कंटेनर बात है।

+0

, आप एक विधि में COM ऑब्जेक्ट है, हमेशा अपवाद फेंकने से पहले उन्हें साफ तो है क्योंकि वे अपवाद फेंकने के बाद साफ नहीं किया जा सकता है ... – prprcupofcoffee

उत्तर

7

आरसीडब्ल्यू आरसीडब्लू को अंतिम रूप देने पर COM ऑब्जेक्ट जारी करेगा, इसलिए आपको ऐसा करने वाला एक रैपर बनाने की आवश्यकता नहीं है। आप ReleaseComObject पर कॉल करते हैं क्योंकि आप अंतिम रूप देने के लिए चारों ओर इंतजार नहीं करना चाहते हैं; यह निपटान पैटर्न के लिए एक ही तर्क है। तो रैपर कि हो सकता है बनाने Dispose घ एक बुरा विचार नहीं है (और वहाँ उदाहरण बाहर वहाँ

var doc = myBrowser.Document.DomDocument ...; के लिए हैं, तो आप भी एक अलग चर में .Document पर कब्जा करना चाहिए और ReleaseComObject यह रूप में अच्छी तरह। आप में से एक संपत्ति को संदर्भित किसी भी समय एक COM वस्तु जो किसी अन्य वस्तु पैदा करता है, इसे जारी करना सुनिश्चित करें।

GetAttribute, आप एक अन्य इंटरफेस करने के लिए तत्व कास्टिंग कर रहे हैं। COM प्रोग्रामिंग, that adds another reference में। तो आप छोड़ सकते हैं आप var htmlElement = (IHTMLElement) element; की तरह कुछ करने की आवश्यकता होगी वह भी।

IHTMLElement element = null; 
try 
{ 
    element = <some method or property returning a COM object>; 
    // do something with element 
} 
catch (Exception ex) // although the exception type should be as specific as possible 
{ 
    // log, whatever 

    throw; // not "throw ex;" - that makes the call stack think the exception originated right here 
} 
finally 
{ 
    if (element != null) 
    { 
     Marshal.ReleaseComObject(element); 
     element = null; 
    } 
} 

यह वास्तव में हर COM ऑब्जेक्ट संदर्भ आप के लिए किया जाना चाहिए: -

संपादित इस पैटर्न जब COM ऑब्जेक्ट के साथ काम करने का प्रयोग है।

+0

क्या इसका मतलब यह है कि उन्हें छोड़ने के बजाय मैं बस कुछ समय में 'जीसी। कोलेक्ट() 'कर सकता हूं और आरसीडब्ल्यू रैपर प्रत्येक COM ऑब्जेक्ट का ख्याल रखेंगे अब कोई संदर्भ नहीं है (यह वास्तव में उन्हें मैन्युअल रूप से रिलीज़ करने से कहीं अधिक आसान लगता है कहीं भी मैं उन हजारों स्थानों की तरह उपयोग करता हूं)? – Juan

+0

मैंने अपनी 'GetAttribute' विधि के बारे में जो सुझाव दिया है, मैंने कोशिश की है और मुझे एक' COM ऑब्जेक्ट मिला है जो इसके अंतर्निहित आरसीडब्लू से अलग किया गया है। 'त्रुटि। ऐसा लगता है कि ऐसा करने से पूरे नोड को केवल 'आईएचटीएमलेमेंट' इंटरफेस नहीं मिलता है। – Juan

+1

आपको निश्चित रूप से कभी भी 'जीसी.कोलेक्ट()' नहीं कहना चाहिए। जब आप इसे कॉल करते हैं तो यह COM ऑब्जेक्ट्स को भी रिलीज़ नहीं करेगा, जरूरी - केवल वे जिन्हें अंतिम रूप देने के लिए पहले ही चिह्नित किया गया है। [यहां एक कोडप्रोजेक्ट आलेख है] (http://www.codeproject.com/Articles/10888/SafeCOMWrapper- प्रबंधित- डिस्पोजेबल- विश्वसनीय- टाइप किया गया) जो आपके साथ किए जाने पर COM ऑब्जेक्ट को मुक्त करने के एक और स्वचालित तरीके पर चर्चा करता है उन्हें। हालांकि, नीचे की रेखा यह है कि जब आप दो प्रणालियों को स्मृति प्रबंधन के बहुत अलग तरीकों से जोड़ते हैं, तो दर्द होना बाध्य होता है। – prprcupofcoffee

1

शायद इस लेख कुछ प्रकाश में लाता है:

MSDN on how COM refcounting works and some basic rules when to call AddRef and Release

आपके मामले में, रिलीज ReleaseComObject

+0

बिल्कुल। एक "संदर्भ" एक COM ऑब्जेक्ट से .NET ऑब्जेक्ट की तुलना में कुछ अलग है, और अंतर को समझना महत्वपूर्ण है। धन्यवाद! – prprcupofcoffee

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

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