Підтримка ESRI каже, що вони відтворили проблему та відкрили звіт про помилку (NIM070156).
Я визначив , що є витік пам'яті (в некерованою динамічної пам'яті) , що відбувається , коли інструмент в моєму .NET / C # ArcMap надбудови виконує просторовий запит (який повертає ICursor
з IFeatureClass.Search
з ISpatialFilter
фільтром запиту). Усі об'єкти COM вивільняються, як тільки вони більше не потрібні (використовуються Marshal.FinalReleaseCOMObject
).
Щоб визначити це, я спершу створив сеанс PerfMon з лічильниками для приватних байтів ArcMap.exe, віртуальних байтів та робочого набору, і зазначив, що всі три сили постійно збільшуються (приблизно в 500 КБ за ітерацію) з кожним використанням інструменту, який виконує запит. . Що головне, це відбувається лише тоді, коли виконується проти класів функцій на SDE за допомогою прямого підключення (ST_Geometry storage, Oracle 11g client and server). Лічильники залишалися постійними при використанні файлової бази даних, а також при підключенні до старого екземпляра SDE, який використовує підключення програми.
Потім я використав LeakDiag та LDGrapher (з деякими вказівками з цієї публікації в блозі ) і тричі реєстрував Windows Heap Allocator: коли я вперше завантажую 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;
}
Ось мій вирішувальний код на основі обговорення нижче з Рагі:
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;
}