ที่อยู่หน่วยความจำรั่วใน IFeatureClass.Search (เฉพาะ SDE ที่มีการเชื่อมต่อโดยตรง) ของ ArcObjects?


16

ฝ่ายสนับสนุนของ ESRI กล่าวว่าพวกเขาทำซ้ำปัญหาและได้เปิดรายงานข้อผิดพลาด (NIM070156)

ผมตั้งใจว่าจะมีการรั่วไหลของหน่วยความจำ (ในความทรงจำที่ไม่มีการจัดการกอง) ที่เกิดขึ้นเมื่อเครื่องมือในของฉัน .NET / C # ArcMap เพิ่มในการดำเนินการสอบถามเชิงพื้นที่ (ส่งคืนICursorจากIFeatureClass.Searchที่มีISpatialFilterตัวกรองแบบสอบถาม) วัตถุ COM ทั้งหมดจะได้รับการปล่อยตัวโดยเร็วที่สุดเท่าที่พวกเขาจะไม่จำเป็น (ใช้Marshal.FinalReleaseCOMObject)

เมื่อต้องการตรวจสอบสิ่งนี้ฉันจะตั้งค่าเซสชัน PerfMon ด้วยตัวนับสำหรับ Private Bytes, Virtual Bytes และ Working Set ของ ArcMap.exe และตั้งข้อสังเกตว่าทั้งสามเพิ่มขึ้นอย่างต่อเนื่อง (โดยประมาณ 500KB ต่อการทำซ้ำ) ด้วยการใช้เครื่องมือแต่ละครั้ง . สิ่งสำคัญนี้จะเกิดขึ้นเฉพาะเมื่อดำเนินการกับคลาสคุณลักษณะบน SDE โดยใช้การเชื่อมต่อโดยตรง (หน่วยเก็บข้อมูล ST_Geometry, ไคลเอ็นต์ Oracle 11g และเซิร์ฟเวอร์) ตัวนับยังคงคงที่เมื่อใช้ Geodatabase ของไฟล์เช่นเดียวกับเมื่อเชื่อมต่อกับอินสแตนซ์ SDE รุ่นเก่าที่ใช้การเชื่อมต่อแอปพลิเคชัน

จากนั้นฉันก็ใช้LeakDiagและLDGrapher (พร้อมคำแนะนำจากบล็อกโพสต์นี้) และบันทึกโปรแกรม Windows Heap Allocator สามครั้ง: เมื่อฉันโหลด ArcMap ครั้งแรกและเลือกเครื่องมือเพื่อเริ่มต้นมันหลังจากใช้เครื่องมือสองสามครั้งและหลังจากทำงาน อีกไม่กี่ครั้ง

นี่คือผลลัพธ์ที่แสดงในมุมมองเริ่มต้นของ LDGrapher (ขนาดโดยรวม): กราฟ LDGrapher แสดงการเพิ่มขึ้นอย่างต่อเนื่องของการใช้หน่วยความจำ

นี่คือ call stack สำหรับสายสีแดง: Call stack แสดงการเรียก sg.dll ไปยังฟังก์ชัน SgsShapeFindRelation2

ในขณะที่คุณสามารถดูSgsShapeFindRelation2ฟังก์ชั่นใน sg.dll ดูเหมือนจะเป็นสิ่งที่รับผิดชอบต่อหน่วยความจำรั่ว

ที่ฉันเข้าใจ sg.dll เป็นห้องสมุดรูปทรงเรขาคณิตหลักที่ใช้โดย ArcObjects และSgsShapeFindRelation2น่าจะเป็นที่ที่ตัวกรองเชิงพื้นที่จะถูกนำไปใช้

ก่อนที่ฉันจะทำสิ่งใดฉันต้องการดูว่ามีใครประสบปัญหานี้หรือไม่ นอกจากนี้สิ่งที่อาจเป็นสาเหตุของสิ่งนี้เกิดขึ้นเฉพาะกับการเชื่อมต่อโดยตรง? เสียงนี้ดูเหมือนข้อบกพร่องใน ArcObjects ปัญหาการกำหนดค่าหรือปัญหาการเขียนโปรแกรมหรือไม่?

นี่เป็นวิธีการทำงานรุ่นที่เล็กที่สุดที่ทำให้เกิดพฤติกรรมนี้

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;
}

นี่คือรหัสการแก้ปัญหาของฉันตามการสนทนาด้านล่างกับ Ragi:

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 การวิเคราะห์ที่ยอดเยี่ยม คุณเห็นมันด้วยการเชื่อมต่อโดยตรงเท่านั้น?
Kirk Kuykendall

เพิ่งทดสอบบนเซิร์ฟเวอร์เก่าที่ใช้การเชื่อมต่อแอปพลิเคชันและไม่มีหน่วยความจำรั่ว ดังนั้นดูเหมือนว่าเฉพาะการเชื่อมต่อโดยตรง!
blah238

ArcGIS เวอร์ชันใด (รวมถึงระดับเซอร์วิสแพ็ค)
Philip

ลูกค้า: ArcGIS 10 SP2, เซิร์ฟเวอร์: ArcGIS 9.3.1 SP1 (ฉันคิดว่าจะตรวจสอบอีกครั้งในวันพรุ่งนี้)
blah238

ไม่จำเป็นต้องพิจารณา oracle driver บางรุ่น แต่มันก็ใช้เวลาสักพัก แต่อาจจะเป็น ODP.NET?
Kirk Kuykendall

คำตอบ:


6

ดูเหมือนว่าข้อผิดพลาด

SG มีไลบรารีเรขาคณิต ArcSDE และไม่ใช่ไลบรารีเรขาคณิต ArcObjects ... มันถูกใช้เป็นตัวกรองล่วงหน้าก่อนการทดสอบจะไปถึงห้องสมุดเรขาคณิต ArcObjects

ลองสิ่งนี้:

ละเว้นบรรทัดนี้:

pSpatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;

และเนื่องจากคุณไม่ได้บันทึกการอ้างอิงไปยังแถวคุณไม่จำเป็นต้องใช้เคอร์เซอร์รีไซเคิลดังนั้นจึงควรเปลี่ยนค่าสถานะเท็จเป็นจริง

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

คุณควรเห็นการปรับปรุงทั้งการใช้หน่วยความจำและความเร็วรันไทม์ อย่างไรก็ตามหากข้อผิดพลาดยังคงถูกโจมตีสิ่งนี้จะหวังว่าจะทำให้เกิดความล่าช้าอย่างมาก :)


1
ขอบคุณ @Ragi - ฉันลองปรับเปลี่ยนทั้งสองอย่าง แต่ไม่มีการเปลี่ยนแปลงในอัตราหน่วยความจำที่รั่วไหลออกมา
blah238

คุณสามารถลองการเชื่อมต่อ 2 ระดับ (เชื่อมต่อโดยตรง) กับ 3 ระดับ (แอพพลิเคชันเซิร์ฟเวอร์) ได้หรือไม่ โดยที่คุณมีเซิร์ฟเวอร์แอปพลิเคชั่นทำงานอยู่นี่ควรเป็นการเปลี่ยนแปลงในสตริงการเชื่อมต่อ sde เท่านั้น
Ragi Yaser Burhum

โอ้เพิ่งเห็นความเห็นของเคิร์กดังนั้นมันจึงเป็นปัญหาการเชื่อมต่อโดยตรง IMHO หากคุณทำสิ่งนี้ด้วย 3 ระดับมีความเป็นไปได้ที่คุณจะเห็นการรั่วไหลในฝั่งเซิร์ฟเวอร์ แต่ลูกค้าจะยังคงเหมือนเดิม ฉันขอถามได้ไหมว่าคุณกำลังทำอะไรกับการแก้ไขหรือการโคลนรูปทรงเรขาคณิต?
Ragi Yaser Burhum

1
ก็ใช่และไม่ใช่ โหมด 3 ระดับ giomgr จะยังคงอยู่และสำหรับการเชื่อมต่อทุกครั้งจะเกิดกระบวนการ gsrvr ใหม่ที่จะตายหลังจากปลดการเชื่อมต่อของคุณดังนั้นหากมีการรั่วไหลที่นั่นก็จะหายไปหลังจากที่คุณตัดการเชื่อมต่อ นอกจากนี้เราไม่สามารถลดความจริงที่ว่าการเชื่อมต่อโดยตรงมีเส้นทางโค้ดที่แตกต่างกันเล็กน้อย ... ลองสองสิ่ง ขั้นแรกให้ปิดตัวกรองเชิงพื้นที่ออกจนหมดแล้วส่งกลับคุณสมบัติแรกแล้วลองเพียงแค่ esriSpatialRelEnvelopeIntersects ฉันรู้ว่า semantically ไม่มีสิ่งเหล่านี้เหมือนกัน แต่เราต้องการติดตามการรั่วไหลก่อน
Ragi Yaser Burhum

3
ใช่ดังนั้นทั้งสองวิธีจึงหลีกเลี่ยงการโทร sgShapeFindRelation2 ลองใช้สิ่งนี้ตอนนี้ esriSpatialRelEnvelopeIntersects บนตัวกรองเชิงพื้นที่เพื่อให้ sde ทำการกรองพื้นฐานขั้นพื้นฐานสุดแล้ว ITopologicalOperator :: ตัดกันเพื่อทำการทดสอบจริงกับลูกค้า สิ่งนี้อาจไม่ได้มีประสิทธิภาพเท่ากับ sgShapeFindRelation2 แต่จะหลีกเลี่ยงการกดปุ่มฟังก์ชันนั้นและจึงหลีกเลี่ยงการรั่วไหล
Ragi Yaser Burhum

4

ถ้าใครยังสนใจในเรื่องนี้มันก็คงที่เวอร์ชั่น 10.1

หมายเลขสนับสนุนทางเทคนิคของ ESRI: 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);
    // ...
}

นอกจากนี้การทำงานกับ Direct Connect ฉันประสบความสำเร็จในการวนSystem.GC.Collect()ซ้ำด้วยการบังคับเป็นระยะ ๆ (ซ้ำหลายครั้ง) แต่ก็ดูน่ารังเกียจ


ฉันให้วิธีของ ComReleaser โดยใช้วิธีของ James MacKay สำหรับการรีไซเคิลเคอร์เซอร์ที่อธิบายไว้ที่นี่: forums.arcgis.com/threads/… - มันไม่ได้สร้างความแตกต่างใด ๆ (มันเป็นเพียงแค่ห่อ Marshal ฉันลองใช้ GC.Collect ด้วย แต่ก็ไม่มีผล ฉันควรจะกล่าวถึงฉันยังดูหน่วยความจำที่มีการจัดการโดยใช้. NET profilers สองและพวกเขาไม่พบวัตถุที่มีการจัดการใด ๆ หรือหน่วยความจำที่มีการจัดการซ้อนขึ้นทำให้ฉันดูหน่วยความจำที่ไม่มีการจัดการ
blah238
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.