Le support ESRI déclare avoir reproduit le problème et ouvert un rapport de bogue (NIM070156).
J'ai déterminé qu'il ya une fuite de mémoire (en mémoire de tas non géré) qui se produit lorsqu'un outil dans mon .NET / C # ArcMap add-in effectue une requête spatiale (un retour ICursor
de IFeatureClass.Search
avec un ISpatialFilter
filtre de requête). Tous les objets COM sont libérés dès qu'ils ne sont plus nécessaires (à l'aide Marshal.FinalReleaseCOMObject
).
Pour déterminer cela, j'ai d'abord configuré une session PerfMon avec des compteurs pour les octets privés, les octets virtuels et le jeu de travail d'ArcMap.exe, et j'ai noté que les trois augmentaient régulièrement (d'environ 500 Ko par itération) à chaque utilisation de l'outil qui exécute la requête . Surtout, cela ne se produit que lorsqu'il est exécuté contre des classes d' entités sur SDE à l'aide d'une connexion directe (stockage ST_Geometry, client et serveur Oracle 11g). Les compteurs sont restés constants lors de l'utilisation d'une géodatabase fichier, ainsi que lors de la connexion à une instance SDE plus ancienne qui utilise la connexion d'application.
J'ai ensuite utilisé LeakDiag et LDGrapher (avec quelques conseils de ce billet de blog ) et j'ai enregistré l'allocateur de tas de Windows à trois reprises: lorsque je charge ArcMap pour la première fois et sélectionne l'outil pour l'initialiser, après avoir exécuté l'outil quelques dizaines de fois et après avoir exécuté quelques dizaines de fois de plus.
Voici les résultats présentés dans la vue par défaut de LDGrapher (taille totale):
Voici la pile d'appels pour la ligne rouge:
Comme vous pouvez le voir, la SgsShapeFindRelation2
fonction dans sg.dll semble être responsable de la fuite de mémoire.
Si je comprends bien, sg.dll est la bibliothèque de géométrie de base utilisée par ArcObjects, et SgsShapeFindRelation2
est probablement là où le filtre spatial est appliqué.
Avant de faire quoi que ce soit d'autre, je voulais juste voir si quelqu'un d'autre avait rencontré ce problème (ou quelque chose de similaire) et si tout ce qu'ils pouvaient faire à ce sujet. De plus, quelle pourrait être la raison pour laquelle cela ne se produit qu'avec une connexion directe? Cela ressemble-t-il à un bogue dans ArcObjects, à un problème de configuration ou à un problème de programmation?
Voici une version de travail minimale de la méthode qui produit ce comportement:
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;
}
Voici mon code de contournement basé sur la discussion ci-dessous avec 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;
}
Réponses:
Cela ressemble à un bug.
SG contient les bibliothèques de géométrie ArcSDE et non les bibliothèques de géométrie ArcObjects ... il est utilisé comme un pré-filtre avant que le test ne frappe les bibliothèques de géométrie ArcObjects.
Essaye ça:
Omettez cette ligne:
pSpatialFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial;
et puisque vous n'enregistrez pas une référence à la ligne, il n'est pas nécessaire que vous n'utilisiez pas de curseurs de recyclage, donc basculez le faux indicateur sur true.
Vous devriez voir une amélioration à la fois de la consommation de mémoire et de la vitesse d'exécution. Néanmoins, si le bogue est toujours rencontré, cela le retardera, espérons-le, de façon spectaculaire :)
la source
Si quelqu'un est toujours intéressé par cela, il a été corrigé dans la version 10.1.
Numéro de support technique ESRI: NIM070156 et NIM062420
http://support.esri.com/en/bugs/nimbus/TklNMDcwMTU2 http://support.esri.com/en/bugs/nimbus/TklNMDYyNDIw
la source
Vous pouvez essayer le modèle suivant au lieu de
try / finally { Marshal.FinalReleaseComObject(...) }
:Travaillant également avec Direct Connect, j'ai eu un certain succès dans les boucles en forçant
System.GC.Collect()
périodiquement (toutes les nombreuses itérations), aussi méchant que cela puisse paraître.la source