ArcObjects: Fuga de memoria en IFeatureClass.Search (solo en SDE con conexión directa)

16

ACTUALIZACIÓN 30/6/11: el soporte de ESRI dice que ha reproducido el problema y ha abierto un informe de error (NIM070156).

He determinado que hay una pérdida de memoria (en la memoria del montón no administrada) que ocurre cuando una herramienta en mi complemento .NET / C # ArcMap realiza una consulta espacial (devolviendo un ICursor desde IFeatureClass.Search con un ISpatialFilter filtro de consulta). Todos los objetos COM se liberan tan pronto como ya no sean necesarios (utilizando Marshal.FinalReleaseCOMObject ).

Para determinar esto, primero configuré una sesión de PerfMon con contadores para los Bytes privados, los Bytes virtuales y el Conjunto de trabajo de ArcMap.exe, y noté que los tres aumentaron constantemente (en aproximadamente 500 KB por iteración) con Cada uso de la herramienta que realiza la consulta. De manera crucial, esto solo ocurre cuando se realiza contra clases de entidad en SDE usando conexión directa (almacenamiento de ST_Geometry, cliente y servidor Oracle 11g). Los contadores se mantuvieron constantes cuando se usa una geodatabase de archivos, así como cuando se conecta a una instancia SDE más antigua que usa la conexión de aplicación.

Luego utilicé LeakDiag y LDGrapher (con alguna orientación de esto blog post ) y registró Windows Heap Allocator en tres ocasiones: la primera vez que cargué ArcMap y seleccioné la herramienta para inicializarla, después de ejecutar la herramienta un par de docenas de veces, y después de ejecutar una docena de veces más.

Estos son los resultados que se muestran en la vista predeterminada de LDGrapher (tamaño total):

Aquíestálapiladellamadasparalalínearoja:

Como puede ver, la función SgsShapeFindRelation2 en sg.dll parece ser la responsable de la pérdida de memoria.

Según entiendo, sg.dll es la biblioteca de geometría central utilizada por ArcObjects, y SgsShapeFindRelation2 es presumiblemente donde se está aplicando el filtro espacial.

Antes de hacer cualquier otra cosa, solo quería ver si alguien más se había topado con este problema (o algo similar) y qué tal si podían hacer algo al respecto. Además, ¿cuál podría ser la razón de que esto ocurra solo con la conexión directa? ¿Suena esto como un error en ArcObjects, un problema de configuración o un problema de programación?

Aquí hay una versión de trabajo mínima del método que produce este comportamiento:

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

Actualización: Aquí está mi código de solución basado en la discusión a continuación con 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;
}
    
pregunta blah238 13.06.2011 - 22:14

3 respuestas

5

Mmmm, parece un error.

SG contiene las bibliotecas de geometría de ArcSDE y no las bibliotecas de geometría de ArcObjects ... se usa como un filtro previo antes de que la prueba llegue a las bibliotecas de geometría de ArcObjects.

Prueba esto:

Omita esta línea:

pSpatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;

y dado que no está guardando una referencia a la fila, no es necesario que no utilice los cursores de reciclaje, por lo que debe cambiar la bandera falsa a verdadero.

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

Debería ver una mejora tanto en el consumo de memoria como en la velocidad de ejecución. Sin embargo, si el error sigue siendo afectado, se espera que esto lo demore dramáticamente :)

    
respondido por el Ragi Yaser Burhum 13.06.2011 - 23:11
3

Si alguien todavía está interesado en esto, se solucionó en la versión 10.1.

Número de soporte técnico de ESRI: NIM070156 y NIM062420

enlace enlace

    
respondido por el travis 16.03.2013 - 00:21
1

¿Alguna vez has probado el siguiente patrón en lugar de try / finally { Marshal.FinalReleaseComObject(...) } ?

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

También trabajando con Direct Connect, he tenido cierto éxito en los bucles al forzar System.GC.Collect() periódicamente (tantas iteraciones), aunque parezca desagradable.

    
respondido por el David Holmes 14.06.2011 - 11:15

Lea otras preguntas en las etiquetas