O suporte da ESRI diz que eles reproduziram o problema e abriram um relatório de erro (NIM070156).
Eu determinei que há um vazamento de memória (na memória heap não gerenciada) que ocorre quando uma ferramenta no meu suplemento .NET / C # ArcMap executa uma consulta espacial (retornando um ICursor
from IFeatureClass.Search
com um ISpatialFilter
filtro de consulta). Todos os objetos COM estão sendo liberados assim que não são mais necessários (usando Marshal.FinalReleaseCOMObject
).
Para determinar isso, primeiro configurei uma sessão do PerfMon com contadores para Bytes Privados, Bytes Virtuais e Conjunto de Trabalho do ArcMap.exe, e observei que os três aumentavam constantemente (em aproximadamente 500 KB por iteração) com cada uso da ferramenta que executa a consulta . Fundamentalmente, isso ocorre apenas quando executado em classes de recurso no SDE usando conexão direta (armazenamento ST_Geometry, cliente e servidor Oracle 11g). Os contadores permaneceram constantes ao usar um geodatabase de arquivo e ao conectar-se a uma instância SDE mais antiga que usa a conexão de aplicativo.
Eu então usei LeakDiag e LDGrapher (com algumas orientações desta postagem do blog ) o Windows Heap Allocator três vezes: quando carrego o ArcMap pela primeira vez e seleciono a ferramenta para inicializá-lo, depois de executá-la algumas dezenas de vezes e depois da execução mais algumas dezenas de vezes.
Aqui estão os resultados mostrados na visualização padrão do LDGrapher (tamanho total):
Aqui está a pilha de chamadas para a linha vermelha:
Como você pode ver, a SgsShapeFindRelation2
função em sg.dll parece ser a responsável pelo vazamento de memória.
Pelo que entendi, o sg.dll é a biblioteca de geometria básica usada pelo ArcObjects, e SgsShapeFindRelation2
provavelmente é onde o filtro espacial está sendo aplicado.
Antes de fazer qualquer outra coisa, eu só queria ver se alguém havia se deparado com esse problema (ou algo semelhante) e se alguma coisa eles pudessem fazer a respeito. Além disso, qual poderia ser o motivo disso ocorrer apenas com a conexão direta? Isso soa como um bug no ArcObjects, um problema de configuração ou um problema de programação?
Aqui está uma versão mínima do método que produz esse 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;
}
Aqui está o meu código de solução alternativa com base na discussão abaixo com o 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;
}