Bộ phận hỗ trợ ESRI cho biết họ đã tái tạo vấn đề và đã mở một báo cáo lỗi (NIM070156).
Tôi đã xác định rằng có một rò rỉ bộ nhớ (trong bộ nhớ heap không được quản lý) xảy ra khi một công cụ trong bổ trợ ArcMap .NET / C # của tôi thực hiện một truy vấn không gian (trả về ICursor
từ IFeatureClass.Search
một ISpatialFilter
bộ lọc truy vấn). Tất cả các đối tượng COM đang được phát hành ngay khi chúng không còn cần thiết (sử dụng Marshal.FinalReleaseCOMObject
).
Để xác định điều này, trước tiên tôi thiết lập phiên PerfMon với các bộ đếm cho Private Byte, Virtual Byte và Work Set của ArcMap.exe và lưu ý rằng cả ba đều tăng đều đặn (khoảng 500KB mỗi lần lặp) với mỗi lần sử dụng công cụ thực hiện truy vấn . Điều quan trọng, điều này chỉ xảy ra khi được thực hiện đối với các lớp tính năng trên SDE bằng cách sử dụng kết nối trực tiếp (lưu trữ ST_Geometry, máy khách và máy chủ Oracle 11g). Các bộ đếm không đổi khi sử dụng cơ sở dữ liệu địa lý tệp, cũng như khi kết nối với một cá thể SDE cũ hơn sử dụng kết nối ứng dụng.
Sau đó, tôi đã sử dụng LeakDiag và LDGograph (với một số hướng dẫn từ bài đăng trên blog này ) và đăng nhập Windows Heap Allocator ba lần: khi tôi tải ArcMap lần đầu tiên và chọn công cụ để khởi tạo nó, sau khi chạy công cụ vài chục lần và sau khi chạy công cụ nó vài chục lần nữa
Dưới đây là các kết quả như được hiển thị trong chế độ xem mặc định của LDGograph (tổng kích thước):
Đây là ngăn xếp cuộc gọi cho đường màu đỏ:
Như bạn có thể thấy SgsShapeFindRelation2
chức năng trong sg.dll dường như là nguyên nhân gây ra rò rỉ bộ nhớ.
Theo tôi hiểu, sg.dll là thư viện hình học lõi được ArcObjects sử dụng và SgsShapeFindRelation2
có lẽ là nơi bộ lọc không gian đang được áp dụng.
Trước khi tôi làm bất cứ điều gì khác, tôi chỉ muốn xem liệu có ai khác gặp phải vấn đề này (hoặc một cái gì đó tương tự) không và nếu có bất cứ điều gì họ có thể làm về vấn đề này. Ngoài ra những gì có thể là lý do cho điều này xảy ra chỉ với kết nối trực tiếp? Điều này có vẻ như là một lỗi trong ArcObjects, vấn đề cấu hình hoặc vấn đề lập trình?
Đây là phiên bản làm việc tối thiểu của phương thức tạo ra hành vi này:
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;
}
Đây là mã giải pháp của tôi dựa trên cuộc thảo luận bên dưới với 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;
}