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;
}
fonte
Respostas:
Isso parece um bug.
O SG contém as bibliotecas de geometria do ArcSDE e não as bibliotecas de geometria do ArcObjects ... é usado como um pré-filtro antes do teste atingir as bibliotecas de geometria do ArcObjects.
Tente o seguinte:
Omita esta linha:
pSpatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;
e como você não está salvando uma referência à linha, não há necessidade de não usar cursores de reciclagem; portanto, mude o sinalizador falso para true.
Você deve ver uma melhoria no consumo de memória e na velocidade de tempo de execução. No entanto, se o bug ainda for atingido, isso provavelmente o atrasará dramaticamente :)
fonte
Se alguém ainda estiver interessado nisso, ele foi corrigido na versão 10.1.
Número de suporte técnico da ESRI: NIM070156 e NIM062420
http://support.esri.com/en/bugs/nimbus/TklNMDcwMTU2 http://support.esri.com/en/bugs/nimbus/TklNMDYyNDIw
fonte
Você pode tentar o seguinte padrão em vez de
try / finally { Marshal.FinalReleaseComObject(...) }
:Além disso, trabalhar com a Direct Connect, eu tive algum sucesso em loops, forçando
System.GC.Collect()
periodicamente (a cada tão muitas iterações), no entanto desagradável que parece.fonte