IFeatureClass.Search में मेमोरी रिसाव को संबोधित करना (केवल सीधे कनेक्ट के साथ एसडीई पर)


16

ईएसआरआई समर्थन का कहना है कि उन्होंने इस मुद्दे को फिर से तैयार किया है और एक बग रिपोर्ट (NIM070156) खोली है।

मैंने निर्धारित किया है कि एक स्मृति रिसाव है (अप्रबंधित हीप मेमोरी में) जो तब होता है जब मेरे .NET / C # ArcMap में एक उपकरण एक स्थानिक क्वेरी को करता है ( एक क्वेरी फ़िल्टर के साथ एक ICursorसे लौटता है )। सभी COM ऑब्जेक्ट को जल्द से जल्द रिलीज़ किया जा रहा है, जिनकी अब आवश्यकता नहीं है (उपयोग करते हुए )।IFeatureClass.SearchISpatialFilterMarshal.FinalReleaseCOMObject

यह निर्धारित करने के लिए, मैंने पहली बार ArcMap.exe के प्राइवेट बाइट्स, वर्चुअल बाइट्स और वर्किंग सेट के लिए काउंटरों के साथ एक परफ़ॉर्मन सत्र की स्थापना की और नोट किया कि क्वेरी को निष्पादित करने वाले टूल के प्रत्येक उपयोग के साथ तीनों में लगातार वृद्धि हुई (लगभग 500KB प्रति पुनरावृत्ति)। । गंभीर रूप से, यह केवल तब होता है जब प्रत्यक्ष कनेक्ट (ST_Geometry स्टोरेज, ओरेकल 11 जी क्लाइंट और सर्वर) का उपयोग करके एसडीई पर फीचर कक्षाओं के खिलाफ प्रदर्शन किया जाता है । फ़ाइल जियोडेटाबेस का उपयोग करते समय काउंटर स्थिर रहे, साथ ही साथ एक पुराने एसडीई उदाहरण से कनेक्ट करना जो एप्लिकेशन कनेक्ट का उपयोग करता है।

मैंने तब LeakDiag और LDGrapher (इस ब्लॉग पोस्ट के कुछ मार्गदर्शन के साथ ) का उपयोग किया और तीन बार में विंडोज हीप एलोकैटर को लॉग इन किया: जब मैंने आर्कप को पहली बार लोड किया और टूल को एक दो बार चलाने के बाद, और इसे चलाने के बाद इसे इनिशियलाइज़ करने के लिए टूल का चयन किया यह कुछ और दर्जन बार है।

यहाँ परिणाम हैं जैसा कि LDGrapher के डिफ़ॉल्ट दृश्य (कुल आकार) में दिखाया गया है: मेमोरी उपयोग पर स्थिर वृद्धि दिखा रहा LDGrapher ग्राफ

यहाँ लाल रेखा के लिए कॉल स्टैक है: कॉल को दिखाने के लिए sg.dll कॉल को SgsShapeFindRelation2 फ़ंक्शन पर कॉल करें

जैसा कि आप देख सकते हैं कि SgsShapeFindRelation2फ़ंक्शन sg.dll में प्रतीत होता है कि मेमोरी लीक के लिए क्या जिम्मेदार है।

जैसा कि मैं समझता हूं कि sg.dll आर्कोबजेक्ट द्वारा उपयोग की जाने वाली कोर ज्योमेट्री लाइब्रेरी है, और SgsShapeFindRelation2संभवतया जहां स्थानिक फ़िल्टर लागू किया जा रहा है।

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

यहां इस पद्धति का एक न्यूनतम कार्यशील संस्करण है जो इस व्यवहार का निर्माण करता है:

private string GetValueAtPoint(IPoint pPoint, IFeatureClass pFeatureClass, string pFieldName)
{
    string results = "";
    ISpatialFilter pSpatialFilter = null;
    ICursor pCursor = null;
    IRow pRow = null;
    try
    {
        pSpatialFilter = new SpatialFilterClass();
        pSpatialFilter.Geometry = pPoint;
        pSpatialFilter.GeometryField = pFeatureClass.ShapeFieldName;
        pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
        pSpatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;
        pCursor = (ICursor)pFeatureClass.Search(pSpatialFilter, false);
        pRow = pCursor.NextRow();
        if (pRow != null)
            results = pRow.get_Value(pFeatureClass.FindField(pFieldName)).ToString();
    }
    finally
    {
        // Explicitly release COM objects
        if (pRow != null)
            Marshal.FinalReleaseComObject(pRow);
        if (pCursor != null)
            Marshal.FinalReleaseComObject(pCursor);
        if (pSpatialFilter != null)
            Marshal.FinalReleaseComObject(pSpatialFilter);
    }
    return results;
}

रागी के साथ नीचे चर्चा पर आधारित मेरा वर्कअराउंड कोड यहां दिया गया है:

private bool PointIntersectsFeature(IPoint pPoint, IFeature pFeature)
{
    bool returnVal = false;
    ITopologicalOperator pTopoOp = null;
    IGeometry pGeom = null;
    try
    {
        pTopoOp = ((IClone)pPoint).Clone() as ITopologicalOperator;
        if (pTopoOp != null)
        {
            pGeom = pTopoOp.Intersect(pFeature.Shape, esriGeometryDimension.esriGeometry0Dimension);
            if (pGeom != null && !(pGeom.IsEmpty))
                returnVal = true;
        }
    }
    finally
    {
    // Explicitly release COM objects
        if (pGeom != null)
            Marshal.FinalReleaseComObject(pGeom);
        if (pTopoOp != null)
            Marshal.FinalReleaseComObject(pTopoOp);
    }
    return returnVal;
}

private string GetValueAtPoint(IPoint pPoint, IFeatureClass pFeatureClass, string pFieldName)
{
    string results = "";
    ISpatialFilter pSpatialFilter = null;
    IFeatureCursor pFeatureCursor = null;
    IFeature pFeature = null;
    try
    {
        pSpatialFilter = new SpatialFilterClass();
        pSpatialFilter.Geometry = pPoint;
        pSpatialFilter.GeometryField = pFeatureClass.ShapeFieldName;
        pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelEnvelopeIntersects;
        pFeatureCursor = pFeatureClass.Search(pSpatialFilter, true);
        pFeature = pFeatureCursor.NextFeature();
        while (pFeature != null)
        {
            if (PointIntersectsFeature(pPoint, pFeature))
            {
                results = pFeature.get_Value(pFeatureClass.FindField(pFieldName)).ToString();
                break;
            }
            pFeature = pFeatureCursor.NextFeature();
        }
    }
    finally
    {
        // Explicitly release COM objects
        if (pFeature != null)
            Marshal.FinalReleaseComObject(pFeature);
        if (pFeatureCursor != null)
            Marshal.FinalReleaseComObject(pFeatureCursor);
        if (pSpatialFilter != null)
            Marshal.FinalReleaseComObject(pSpatialFilter);
    }
    return results;
}

1
+1 महान विश्लेषण। क्या आप इसे केवल डायरेक्ट कनेक्ट के साथ देख रहे हैं ?
कर्क कूकेन्डल

बस एक पुराने सर्वर पर इसका परीक्षण किया है जो एप्लिकेशन कनेक्ट का उपयोग करता है और वहां कोई मेमोरी लीक नहीं है। तो यकीन है कि सीधे कनेक्ट करने के लिए विशिष्ट लगता है!
blah238

ArcGIS का कौन सा संस्करण (सर्विस पैक स्तर सहित)?
फिलिप

क्लाइंट: आर्कगिस 10 SP2, सर्वर: ArcGIS 9.3.1 SP1 (मुझे लगता है, कल दोहरी जांच होगी)।
blah238

क्या कुछ ओरेकल ड्राइवर संस्करण है जिस पर आपको विचार करने की आवश्यकता है, यह थोड़ी देर के लिए है, लेकिन शायद ODP.NET?
किर्क कुएकेन्डल

जवाबों:


6

यह बग जैसा दिखता है।

SG में ArcSDE ज्योमेट्री लाइब्रेरियाँ हैं न कि आर्कोबजेक्ट्स ज्योमेट्री लाइब्रेरियाँ ... इसका इस्तेमाल प्री-फिल्टर के रूप में किया जाता है, इससे पहले कि अर्कबजेक्ट्स ज्योमेट्री लाइब्रेरीज़ को हिट करें।

इसे इस्तेमाल करे:

इस पंक्ति को स्वीकार करें:

pSpatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;

और चूंकि आप पंक्ति के संदर्भ को नहीं सहेज रहे हैं, इसलिए आपके लिए कोई ज़रूरत नहीं है कि आप रिसाइकिलिंग कर्सर का उपयोग न करें, इसलिए झूठे झंडे को सही पर स्विच करें।

pCursor = (ICursor)pFeatureClass.Search(pSpatialFilter, true);

आपको मेमोरी खपत और रनटाइम गति दोनों में सुधार देखना चाहिए। फिर भी, अगर बग अभी भी हिट है, तो यह नाटकीय रूप से नाटकीय रूप से देरी करेगा :)


1
धन्यवाद @ रागी - मैंने दोनों संशोधनों की कोशिश की लेकिन मेमोरी के लीक होने की दर में कोई बदलाव नहीं हुआ।
blah238

क्या आप 2 स्तरीय (डायरेक्ट कनेक्ट) बनाम 3 टीयर (एप्लिकेशन सर्वर) कनेक्शन की कोशिश कर सकते हैं? बशर्ते आपके पास एप्लिकेशन सर्वर पहले से चल रहा हो, यह केवल sde कनेक्शन स्ट्रिंग में बदलाव होना चाहिए।
रागी यासर बुरहुम

ओह, सिर्फ कर्क की टिप्पणी देखी, इसलिए यह एक सीधा कनेक्ट मुद्दा है। IMHO, यदि आपने 3 स्तरीय के साथ ऐसा किया है, तो यह सुनिश्चित करने की क्षमता है कि आपको सर्वर की तरफ रिसाव दिखाई देगा, लेकिन क्लाइंट वॉल्ड एक ही रहेगा। क्या मैं पूछ सकता हूं कि क्या आप संपादन या क्लोनिंग के साथ कुछ भी कर रहे हैं?
रागी यशर बुरहं

1
खैर, हाँ और नहीं। 3 स्तरीय मोड, जिओमग्र निवासी रहता है और हर कनेक्शन के लिए यह एक नई gsrvr प्रक्रिया को जन्म देता है जो आपके डिस्कनेक्ट के बाद मर जाएगी, इसलिए यदि रिसाव था, तो आपके डिस्कनेक्ट होने के बाद यह चला जाएगा। इसके अलावा, हम इस तथ्य पर छूट नहीं दे सकते हैं कि प्रत्यक्ष कनेक्ट में बहुत अलग कोड पथ है ... दो चीजों का प्रयास करें। एक, बस स्थानिक फ़िल्टर को पूरी तरह से बंद करें और पहली विशेषता को वापस लौटाएं, फिर केवल esriSpatialRelEnvelopeIntersects आज़माएं। मुझे पता है कि शब्दार्थ इनमें से कोई भी समान नहीं है, लेकिन हम पहले लीक को ट्रैक करना चाहते हैं।
रागी यशर बुरहं

3
हाँ, इसलिए दोनों विधियाँ कॉल sgShapeFindRelation2 से बच रही हैं। अब यह कोशिश करो, sri बनाने के लिए स्थानिक फिल्टर पर esriSpatialRelEnvelopeIntersects सुपर बुनियादी पूर्व फ़िल्टरिंग करते हैं, और फिर ITopologicalOperator :: क्लाइंट पर वास्तविक परीक्षण करने के लिए प्रतिच्छेद करते हैं। यह sgShapeFindRelation2 जितना कुशल नहीं हो सकता है, लेकिन यह उस फ़ंक्शन को हिट करने से बचाएगा और इसलिए रिसाव से बचें।
रागी यासर बुरहुम

4

अगर किसी को अभी भी इसमें दिलचस्पी है, तो यह संस्करण 10.1 पर तय किया गया था।

ईएसआरआई तकनीकी सहायता संख्या: NIM070156 और NIM062420

http://support.esri.com/en/bugs/nimbus/TklNMDcwMTU2 http://support.esri.com/en/bugs/nimbus/TklNMDYyNDIw


यह संस्करण निश्चित के लिए कुछ भी सूचीबद्ध नहीं करता है, इसलिए मुझे लगता है कि मुझे सिर्फ इसके लिए अपना शब्द लेना होगा। मैंने 10.1 पर परीक्षण नहीं किया है। मेरी बग रिपोर्ट में समस्या का लेबल लगाने से कोई लेना-देना नहीं है, इसलिए सुनिश्चित नहीं है कि उन्होंने इसे दूसरे के डुप्लिकेट के रूप में चिह्नित किया है।
blah238

1

आप इसके बजाय निम्नलिखित पैटर्न आज़मा सकते हैं try / finally { Marshal.FinalReleaseComObject(...) }:

using (ESRI.ArcGIS.ADF.ComReleaser cr) {
    var cursor = (ICursor) fc.Search(...);
    cr.ManageLifetime(cursor);
    // ...
}

डायरेक्ट कनेक्ट के साथ काम करते हुए, मुझे System.GC.Collect()समय-समय पर (हर इतने सारे पुनरावृत्तियों) को मजबूर करके छोरों में कुछ सफलता मिली है , हालांकि बुरा लग रहा है।


मैंने ComReleaser को यहां वर्णित कर्सरों को रीसाइक्लिंग के लिए जेम्स मैकके की विधि का उपयोग करते हुए एक शॉट दिया: मंचों . arcgis.com/threads/… - इससे कोई फर्क नहीं पड़ा (यह सिर्फ मार्शल को लपेटता है ।eleaseCOMObobb वैसे भी बहुत आश्चर्य की बात नहीं है)। मैंने GC.Collect का उपयोग करने की भी कोशिश की है लेकिन इसका भी कोई असर नहीं हुआ। मैंने उल्लेख किया है कि मैंने प्रबंधित मेमोरी को .NET प्रोफाइलरों के एक जोड़े का उपयोग करके देखा है और उनमें से किसी को भी कोई प्रबंधित ऑब्जेक्ट नहीं मिला या मेमोरी पाइलिंग प्रबंधित नहीं हुई, जिससे मुझे अनवांटेड मेमोरी देखने में मदद मिली।
blah238
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.