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 de 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 lanzan tan pronto como ya no se necesitan (usando Marshal.FinalReleaseCOMObject
).
Para determinar esto, primero configuré una sesión de PerfMon con contadores para Bytes privados, Bytes virtuales y Conjunto de trabajo de ArcMap.exe, y noté que los tres aumentaron constantemente (aproximadamente 500 KB por iteración) con cada uso de la herramienta que realiza la consulta . Crucialmente, esto solo ocurre cuando se realiza contra clases de entidad en SDE usando conexión directa (almacenamiento ST_Geometry, cliente y servidor Oracle 11g). Los contadores permanecieron constantes al usar una geodatabase de archivos, así como al conectarse a una instancia SDE anterior que usa la conexión de aplicaciones.
Luego utilicé LeakDiag y LDGrapher (con alguna guía de esta publicación de blog ) y registré el Windows Heap Allocator en tres ocasiones: cuando cargo ArcMap por primera vez y selecciono la herramienta para inicializarla, después de ejecutar la herramienta un par de docenas de veces, y después de ejecutarla unas pocas docenas más de veces.
Estos son los resultados que se muestran en la vista predeterminada de LDGrapher (tamaño total):
Aquí está la pila de llamadas para la línea roja:
Como puede ver, la SgsShapeFindRelation2
función en sg.dll parece ser la responsable de la pérdida de memoria.
Según tengo entendido, sg.dll es la biblioteca de geometría central utilizada por ArcObjects, y SgsShapeFindRelation2
presumiblemente es donde se aplica 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é 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 mínima de trabajo 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;
}
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;
}