ESRI 지원팀은 문제를 재현했으며 버그 보고서 (NIM070156)를 열었다 고 말합니다.
.NET / C # ArcMap 애드 인의 도구가 공간 쿼리 ( 쿼리 필터 ICursor
를 IFeatureClass.Search
사용하여 반환)를 수행 할 때 발생하는 메모리 누수 (관리되지 않는 힙 메모리에서)가 ISpatialFilter
있음을 확인했습니다. 더 이상 필요하지 않은 즉시 모든 COM 개체가 해제됩니다 (사용 Marshal.FinalReleaseCOMObject
).
이를 확인하기 위해 먼저 ArcMap.exe의 Private Bytes, Virtual Bytes 및 Working Set에 대한 카운터를 사용하여 PerfMon 세션을 설정 하고 쿼리를 수행하는 도구를 사용할 때마다 세 가지 모두 꾸준히 증가합니다 (반복 당 약 500KB). . 결정적으로 이것은 직접 연결 (ST_Geometry 스토리지, Oracle 11g 클라이언트 및 서버)을 사용하여 SDE의 기능 클래스에 대해 수행 될 때만 발생합니다 . 파일 지오 데이터베이스를 사용할 때와 응용 프로그램 연결을 사용하는 이전 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;
}