Служба поддержки ESRI сообщает, что они воспроизвели проблему и открыли отчет об ошибке (NIM070156).
Я определил, что существует утечка памяти (в неуправляемой динамической памяти), которая возникает, когда инструмент в моей надстройке .NET / C # ArcMap выполняет пространственный запрос (возвращая объект ICursor
from IFeatureClass.Search
с ISpatialFilter
фильтром запроса). Все COM-объекты освобождаются, как только они больше не нужны (используя Marshal.FinalReleaseCOMObject
).
Чтобы определить это, я сначала настроил сеанс PerfMon со счетчиками для личных байтов, виртуальных байтов и рабочего набора ArcMap.exe и отметил, что все три постоянно увеличиваются (примерно на 500 КБ за итерацию) с каждым использованием инструмента, выполняющего запрос , Важно отметить, что это происходит только при выполнении с классами пространственных объектов в SDE с использованием прямого соединения (хранилище ST_Geometry, клиент и сервер Oracle 11g). Счетчики оставались постоянными при использовании файловой базы геоданных, а также при подключении к более старому экземпляру SDE, в котором используется подключение к приложению.
Затем я использовал LeakDiag и LDGrapher (с некоторыми рекомендациями из этого поста в блоге ) и трижды регистрировал распределитель кучи Windows: при первой загрузке ArcMap и выборе инструмента для его инициализации, после запуска инструмента пару раз и после запуска это еще несколько десятков раз.
Вот результаты, показанные в представлении LDGrapher по умолчанию (общий размер):
Вот стек вызовов для красной линии:
Как вы можете видеть, SgsShapeFindRelation2
функция sg.dll отвечает за утечку памяти.
Как я понимаю, sg.dll - это библиотека геометрии ядра, используемая ArcObjects, и SgsShapeFindRelation2
предположительно там, где применяется пространственный фильтр.
Прежде чем делать что-то еще, я просто хотел посмотреть, сталкивался ли кто-нибудь еще с этой проблемой (или чем-то подобным) и что если они могли бы что-то сделать с этим. Кроме того, что может быть причиной этого только при прямом подключении? Похоже ли это на ошибку в ArcObjects, проблему конфигурации или проблему программирования?
Вот минимальная рабочая версия метода, который производит это поведение:
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;
}
Вот мой обходной код, основанный на обсуждении ниже с 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;
}