ESRI支持人员说,他们已重现了该问题,并已打开一个错误报告(NIM070156)。
我已确定,有内存泄漏(在非托管堆内存)时发生在工具我的.NET / C#ArcMap中附加执行空间查询(返回ICursor
从IFeatureClass.Search
与ISpatialFilter
查询过滤器)。不再需要所有COM对象时,它们将被释放(使用Marshal.FinalReleaseCOMObject
)。
为了确定这一点,我首先建立了一个带有ArcMap.exe的“专用字节”,“虚拟字节”和“工作集”计数器的PerfMon会话,并注意到,随着执行查询的工具的每次使用,这三者均稳步增加(每次迭代大约增加 500KB) 。至关重要的是,只有在使用直接连接(ST_Geometry存储,Oracle 11g客户端和服务器)对SDE上的要素类执行此操作时,才会发生这种情况。使用文件地理数据库以及连接到使用应用程序连接的较旧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;
}
这是基于下面与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;
}