Il supporto ESRI afferma di aver riprodotto il problema e di aver aperto una segnalazione di bug (NIM070156).
Ho determinato che esiste una perdita di memoria (nella memoria heap non gestita) che si verifica quando uno strumento nel mio componente aggiuntivo ArcMap .NET / C # esegue una query spaziale (restituendo un ICursor
da IFeatureClass.Search
con un ISpatialFilter
filtro di query). Tutti gli oggetti COM vengono rilasciati non appena non sono più necessari (utilizzando Marshal.FinalReleaseCOMObject
).
Per determinare ciò, ho prima impostato una sessione PerfMon con contatori per i byte privati, i byte virtuali e il working set di ArcMap.exe e ho notato che tutti e tre sono aumentati costantemente (di circa 500 KB per iterazione) con ogni utilizzo dello strumento che esegue la query . Fondamentalmente, ciò si verifica solo se eseguito su classi di funzionalità su SDE utilizzando la connessione diretta (archiviazione ST_Geometry, client e server Oracle 11g). I contatori sono rimasti costanti durante l'utilizzo di un geodatabase di file, nonché durante la connessione a un'istanza SDE precedente che utilizza la connessione dell'applicazione.
Ho quindi usato LeakDiag e LDGrapher (con alcune indicazioni da questo post sul blog ) e ho registrato l'allocatore di heap di Windows tre volte: quando ho caricato ArcMap per la prima volta e ho selezionato lo strumento per inizializzarlo, dopo averlo eseguito una dozzina di volte e dopo averlo eseguito qualche altra dozzina di volte.
Ecco i risultati come mostrato nella vista predefinita di LDGrapher (dimensione totale):
Ecco lo stack di chiamate per la linea rossa:
Come puoi vedere, la SgsShapeFindRelation2
funzione in sg.dll sembra essere ciò che è responsabile della perdita di memoria.
A quanto ho capito sg.dll è la libreria di geometria di base utilizzata da ArcObjects ed SgsShapeFindRelation2
è presumibilmente in cui viene applicato il filtro spaziale.
Prima di fare qualsiasi altra cosa, volevo solo vedere se qualcun altro si era imbattuto in questo problema (o qualcosa di simile) e cosa se qualcosa fosse stato in grado di fare al riguardo. Inoltre, quale potrebbe essere la ragione per cui ciò si verifica solo con la connessione diretta? Suona come un bug in ArcObjects, un problema di configurazione o un problema di programmazione?
Ecco una versione minima del metodo che produce questo comportamento:
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;
}
Ecco il mio codice di soluzione basato sulla discussione di seguito 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;
}