ArcObjects IFeatureClass.Search (sadece doğrudan bağlantılı SDE üzerinde) bellek sızıntısı gidermek için?


16

ESRI Desteği, sorunu yeniden oluşturduklarını ve bir hata raporu açtıklarını söylüyor (NIM070156).

Benim .NET / C # ArcMap eklenti bir araç ( bir sorgu filtresi ile ICursorgelen dönen) bir uzamsal sorgu gerçekleştirdiğinde oluşan bir bellek sızıntısı (yönetilmeyen yığın bellek) olduğunu belirledim . Tüm COM nesneleri artık gerekli olmadıkları anda serbest bırakılıyor (kullanılıyor ).IFeatureClass.SearchISpatialFilterMarshal.FinalReleaseCOMObject

Bunu belirlemek için önce ArcMap.exe'nin Özel Baytları, Sanal Baytlar ve Çalışma Kümesi için sayaçlarla bir PerfMon oturumu kurdum ve üçünü de sorguyu gerçekleştiren aracın her kullanımıyla birlikte sürekli olarak arttı (kabaca 500 KB). . Bu, yalnızca doğrudan bağlantı (ST_Geometry depolama, Oracle 11g istemci ve sunucu) kullanılarak SDE'deki özellik sınıflarına karşı gerçekleştirildiğinde gerçekleşir . Sayaçlar, bir dosya coğrafi veritabanı kullanılırken ve ayrıca uygulama bağlantısı kullanan eski bir SDE örneğine bağlanırken sabit kaldı.

Daha sonra LeakDiag ve LDGrapher kullandım (bu blog gönderisinden bazı rehberlikle ) ve Windows Yığın Allocator'u üç kez kaydettim: ArcMap'ı ilk yüklediğimde ve aracı başlatmak için aracı birkaç düzine çalıştırdıktan sonra ve çalıştırdıktan sonra birkaç düzine kez daha.

LDGrapher'in varsayılan görünümünde (toplam boyut) gösterilen sonuçlar şunlardır: Bellek kullanımında sürekli artış gösteren LDGrapher grafiği

İşte kırmızı hat için çağrı yığını: Sgs.dll çağrısı SgsShapeFindRelation2 işlevini gösteren çağrı yığını

Gördüğünüz gibi SgsShapeFindRelation2sg.dll işlevi bellek sızıntısından sorumlu gibi görünüyor.

Anladığım kadarıyla sg.dll ArcObjects tarafından kullanılan çekirdek geometri kütüphanesi ve SgsShapeFindRelation2muhtemelen mekansal filtre uygulandığı yerdir.

Başka bir şey yapmadan önce, başka birinin bu sorunla (veya benzer bir şeyle) karşılaşıp karşılaşmadığını ve bu konuda yapabildikleri herhangi bir şey olup olmadığını görmek istedim. Ayrıca, bunun yalnızca doğrudan bağlantıda gerçekleşmesinin nedeni ne olabilir? ArcObjects'teki bir hata, bir yapılandırma sorunu veya bir programlama sorunu gibi görünüyor mu?

İşte bu davranışı üreten yöntemin en az çalışan bir sürümü:

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

İşte Ragi ile ilgili tartışmaya dayanan geçici çözüm kodum:

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 harika analiz. Sadece doğrudan bağlantı ile mi görüyorsunuz ?
Kirk Kuykendall

Sadece uygulama bağlantısı kullanan eski bir sunucuda test edildi ve orada bellek sızıntısı yok. Bu yüzden doğrudan bağlantıya özgü görünüyor!
blah238

Hangi ArcGIS sürümü (hizmet paketi düzeyi dahil)?
Philip

İstemci: ArcGIS 10 SP2, Sunucu: ArcGIS 9.3.1 SP1 (Sanırım yarın tekrar kontrol edecek).
blah238

Dikkate almanız gereken bazı oracle sürücü sürümü yok, bir süre oldu, ama belki ODP.NET?
Kirk Kuykendall

Yanıtlar:


6

Bu bir hata gibi görünüyor.

SG, ArcObjects geometri kitaplıklarını değil ArcSDE geometri kitaplıklarını içerir ... test ArcObjects geometri kitaplıklarına çarpmadan önce bir ön filtre olarak kullanılır.

Bunu dene:

Bu satırı atlayın:

pSpatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;

ve satıra bir referans kaydetmediğiniz için, geri dönüşüm imleçlerini kullanmanıza gerek yoktur, bu nedenle yanlış bayrağı true olarak değiştirin.

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

Hem bellek tüketiminde hem de çalışma süresinde bir iyileşme görmelisiniz. Yine de, hata hala vurulursa, bu umarım önemli ölçüde geciktirir :)


1
Teşekkürler @Ragi - Her iki değişikliği de denedim ama sızan bellek oranında bir değişiklik yoktu.
blah238

2 katmanlı (doğrudan bağlantı) ve 3 katmanlı (uygulama sunucusu) bağlantıyı deneyebilir misiniz? uygulama sunucusu zaten çalışıyorsa, bu yalnızca sde bağlantı dizesinde bir değişiklik olmalıdır.
Ragi Yaser Burhum

oh, sadece kirk'ın yorumunu gördüm, bu yüzden doğrudan bağlantı sorunu. IMHO, bunu 3 katmanlı yaptıysanız, sunucu tarafında sızıntı göreceğiniz olasılık var, ancak istemci aynı kalacak. Düzenlemeler veya klonlama geometrileriyle bir şey yapıp yapmadığınızı sorabilir miyim?
Ragi Yaser Burhum

1
Evet, hayır. 3 kademeli mod, giomgr yerleşik olarak kalır ve her bağlantı için, bağlantıyı kestikten sonra ölecek yeni bir gsrvr işlemi oluşturur, bu nedenle sızıntı orada olsaydı, bağlantıyı kestikten sonra gider. Ayrıca, doğrudan bağlantının çok az farklı bir kod yoluna sahip olduğu gerçeğini de indiremeyiz ... İki şeyi deneyin. Birincisi, uzamsal filtreyi tamamen kapatın ve ilk özelliği döndürün ve sonra sadece esriSpatialRelEnvelopeIntersects'i deneyin. Anlamsal olarak bunların hiçbirinin aynı olmadığını biliyorum, ama önce sızıntıyı izlemek istiyoruz.
Ragi Yaser Burhum

3
Evet, her iki yöntem de sgShapeFindRelation2 çağrısından kaçınıyor. Şimdi deneyin, esriSpatialRelEnvelopeInde'nin sde'nin süper temel bir ön filtreleme yapmasını sağlamak için uzamsal filtre üzerinde kesişir ve ardından ITopologicalOperator :: istemcide gerçek testi yapmak için kesişir. Bu, sgShapeFindRelation2 kadar etkili olmayabilir, ancak bu işleve çarpmamaktan ve dolayısıyla sızıntıdan kaçınmaktan kaçınacaktır.
Ragi Yaser Burhum

4

Hala bununla ilgilenen varsa, Sürüm 10.1'de düzeltildi.

ESRI Teknik Destek Numarası: NIM070156 ve NIM062420

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


Sürüm Sabit için hiçbir şey listelemez, bu yüzden sanırım sadece sözünü almam gerekecek. Yine de 10.1'de test etmedim. Ayrıca benim hata raporunda sorun etiketleme ile ilgisi yoktur, bu yüzden neden diğerinin bir kopyası olarak işaretlenmiş emin değilim.
blah238 16:13

1

Bunun yerine aşağıdaki kalıbı deneyebilirsiniz try / finally { Marshal.FinalReleaseComObject(...) }:

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

Ayrıca Direct Connect ile çalışarak, System.GC.Collect()periyodik olarak (her çok yineleme) zorlayarak döngülerde bazı başarılar elde ettim , ancak kötü görünüyor.


ComReleaser yaklaşımına James MacKay'ın burada açıklanan imleçleri geri dönüştürme yöntemini kullanarak bir şans verdim : forums.arcgis.com/threads/… - herhangi bir fark yaratmadı (sadece Marshal.ReleaseCOMObject'i zaten çok şaşırtıcı değil). Ben de GC.Collect kullanarak denedim ama aynı zamanda bir etkisi yoktu. Ayrıca birkaç .NET profiler kullanarak yönetilen belleğe baktım ve hiçbiri herhangi bir yönetilen nesne veya yönetilen bellek bulamadı, bu yüzden yönetilmeyen belleğe bakmamı sağladı.
blah238
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.