GetFeature causing memory leak when editing

399
1
05-16-2018 09:43 AM
WilliamBuerger
Occasional Contributor

I've know that some of our custom tools occasionally run into memory leaks from time to time.  Usually, we just run the tool in smaller batches to get through it.  But after doing some investigation, I finally tracked down where the problem is coming from.  It would seem that calling IFeatureClass.GetFeature or IStandaloneTable.GetRow on a table that is currently being edited, causes the row to not be released.  I tried using Marshal.FinalReleaseComObject to force it to release the feature but it didn't help.  I think I had some minor success or improvement by doing that and forcing garbage collection.  But it didn't fix everything.  If you do the same thing on a table that is not being edited, there's no issue.  Maybe there's something in the editor extension that is grabbing on to features that are being retrieved and not letting go of them.

Here is some sample code I created that shows the issue.  It gets the OID of all of the features in the first layer in your map and puts them into an array.  Then goes through those OIDs and calls GetFeature for each one.

var StartTime = DateTime.Now;
var Count = 0;
var Total = 0;
var Layer = (IFeatureLayer)mxDoc.FocusMap.get_Layer(0);
var Cursor = Layer.FeatureClass.Search(null, true);
var OIDs = new List<int>();
var Feat = (IFeature) null;


try
{
   while ((Feat = Cursor.NextFeature()) != null)
   {
      OIDs.Add(Feat.OID);
      Total++;
   }
}
finally
{
   Marshal.FinalReleaseComObject(Cursor);
}

foreach (var OID in OIDs)
{
   if (Count % 1000 == 0)
   {
      var Ts = DateTime.Now - StartTime;
      MxApp.StatusBar.set_Message(0,

         string.Format("{0:#,0}s - {1:#,0}/{2:#,0} - GetFeature()...", Ts.TotalSeconds, Count, Total));
      Application.DoEvents();
   }

   Feat = Layer.FeatureClass.GetFeature(OID);
   System.Runtime.InteropServices.Marshal.FinalReleaseComObject(Feat);
   Feat = null;
   Count++;
}

Attached is a video showing this code executing.  I've included Task Manager so you can watch the memory increase as it goes.  I've sped it up about 12x as it takes a few minutes to get through the whole thing.  If you run this with the layer not being edited, then there's no issue and memory usage never goes over about 200MB.

Tags (2)
0 Kudos
1 Reply
WilliamBuerger
Occasional Contributor

Forgot to mention that the workaround for this issue is to just use GetRows/GetFeatures passing the one OID and grab the first record from the cursor.  This has the added benefit that GetRows doesn't through an exception when the OID doesn't exist.  Then I can return null and deal with that instead of having to handle an exception.

0 Kudos