Der ESRI-Support gibt an, das Problem reproduziert und einen Fehlerbericht geöffnet zu haben (NIM070156).
Ich habe festgestellt, dass ein Speicherverlust (im nicht verwalteten Heap-Speicher) vorliegt, der auftritt, wenn ein Tool in meinem .NET / C # ArcMap-Add-In eine räumliche Abfrage ausführt (und mit einem Abfragefilter ein ICursor
from zurückgibt ). Alle COM-Objekte werden freigegeben, sobald sie nicht mehr benötigt werden (mit ).IFeatureClass.Search
ISpatialFilter
Marshal.FinalReleaseCOMObject
Um dies festzustellen, habe ich zuerst eine PerfMon-Sitzung mit Leistungsindikatoren für die privaten Bytes, virtuellen Bytes und den Arbeitssatz von ArcMap.exe eingerichtet und festgestellt, dass alle drei mit jeder Verwendung des Tools, das die Abfrage ausführt, stetig zunahmen (um ca. 500 KB pro Iteration) . Entscheidend ist, dass dies nur bei der Ausführung von Feature-Classes unter SDE unter Verwendung einer direkten Verbindung (ST_Geometry-Speicher, Oracle 11g-Client und -Server) auftritt. Die Leistungsindikatoren blieben konstant, wenn eine File-Geodatabase verwendet wurde sowie eine Verbindung zu einer älteren SDE-Instanz hergestellt wurde, die Application Connect verwendet.
Ich habe dann LeakDiag und LDGrapher (mit einigen Anleitungen aus diesem Blogbeitrag ) verwendet und den Windows-Heap-Allocator dreimal protokolliert: Beim ersten Laden von ArcMap und Auswählen des zu initialisierenden Tools, nachdem das Tool ein paar Dutzend Mal ausgeführt wurde und nachdem es ausgeführt wurde es noch ein paar Dutzend Mal.
Die folgenden Ergebnisse werden in der Standardansicht von LDGrapher angezeigt (Gesamtgröße):
Hier ist die Aufrufliste für die rote Linie:
Wie Sie sehen, SgsShapeFindRelation2
scheint die Funktion in sg.dll für den Speicherverlust verantwortlich zu sein.
Soweit ich weiß, ist sg.dll die von ArcObjects verwendete Geometrie-Kernbibliothek. SgsShapeFindRelation2
Vermutlich wird dort der räumliche Filter angewendet.
Bevor ich etwas anderes mache, wollte ich nur sehen, ob jemand anderes auf dieses Problem gestoßen ist (oder etwas Ähnliches) und was, wenn er in der Lage ist, etwas dagegen zu unternehmen. Auch was könnte der Grund dafür sein, dass dies nur bei direkter Verbindung auftritt? Klingt dies nach einem Fehler in ArcObjects, einem Konfigurationsproblem oder einem Programmierproblem?
Hier ist eine minimale Arbeitsversion der Methode, die dieses Verhalten erzeugt:
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;
}
Hier ist mein Workaround-Code, der auf der folgenden Diskussion mit Ragi basiert:
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;
}
quelle
Antworten:
Das sieht aus wie ein Bug.
SG enthält die ArcSDE-Geometriebibliotheken und nicht die ArcObjects-Geometriebibliotheken. Es wird als Vorfilter verwendet, bevor der Test die ArcObjects-Geometriebibliotheken erreicht.
Versuche dies:
Lass diese Zeile weg:
pSpatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;
und da Sie keinen Verweis auf die Zeile speichern, müssen Sie keine Recycling-Cursor verwenden. Setzen Sie daher das false-Flag auf true.
Sie sollten eine Verbesserung sowohl des Speicherverbrauchs als auch der Laufzeitgeschwindigkeit feststellen. Sollte der Fehler dennoch auftreten, wird er hoffentlich dramatisch verzögert :)
quelle
Wenn noch jemand daran interessiert ist, wurde es auf Version 10.1 behoben.
ESRI Technical Support Number: NIM070156 und NIM062420
http://support.esri.com/de/bugs/nimbus/TklNMDcwMTU2 http://support.esri.com/de/bugs/nimbus/TklNMDYyNDIw
quelle
Sie könnten stattdessen das folgende Muster ausprobieren
try / finally { Marshal.FinalReleaseComObject(...) }
:Ich habe auch mit Direct Connect gearbeitet und habe einige Erfolge in Schleifen erzielt, indem ich in
System.GC.Collect()
regelmäßigen Abständen (bei so vielen Iterationen) Forcen durchgeführt habe, wie böse es auch aussieht.quelle