[GIS] ArcObjects Memory Leak with IWorkspaceEdit

arcobjectsbuffercenterprise-geodatabasememory

I have ArcGIS 10.1 installed.
I have created a function for copying all of the features from one shapefile to another using IFeatureBuffer, now every time the function when it is called, it takes some memory, but doesn't release that much, meaning on every function call a memory leak happens. What i have observed is that the memory leak is dependent upon the size of the shapefile, I imported the shapefile with around 34000 features, and the memory leak was much greater than that with a smaller shapefile. Following is the minimal code version of this behaviour:

public void CopyFeatures(string srcFile, string srcDir, string outFile, string outDir)
{
    IWorkspaceFactory workspaceFactory = new ESRI.ArcGIS.DataSourcesFile.ShapefileWorkspaceFactory();
    IWorkspace workspace = workspaceFactory.OpenFromFile(srcDir, 0);        
    IFeatureClass featureClass = ((IFeatureWorkspace)workspace).OpenFeatureClass(srcFile);
    IFeatureCursor featureCursor = featureClass.Search(null, false);
    IFeature feature = featureCursor.NextFeature();

    IWorkspace outputWorkspace = workspaceFactory.OpenFromFile(outDir, 0);
    IFeatureClass outputFeatureClass = ((IFeatureWorkspace)outputWorkspace).CreateFeatureClass(outFile, featureClass.Fields, null, null, esriFeatureType.esriFTSimple, "Shape", "");

    IWorkspaceEdit workspaceEdit = ((IDataset)outputFeatureClass).Workspace as IWorkspaceEdit;
    if (!workspaceEdit.IsBeingEdited())
    {
        workspaceEdit.StartEditing(false);
        workspaceEdit.StartEditOperation();
    }

    IFeatureBuffer outputFeatureBuffer = outputFeatureClass.CreateFeatureBuffer();
    IFeatureCursor outputFeatureCursor = outputFeatureClass.Insert(true);

    while (feature != null)
    {
        for (int i = 0; i < outputFeatureBuffer.Fields.FieldCount; i++)
        {
            IField field = feature.Fields.Field[i];
            string myName = field.Name;
            if (field.Editable == true)
                outputFeatureBuffer.Value[outputFeatureBuffer.Fields.FindField(myName)] = feature.Value[feature.Fields.FindField(myName)];
        }

        outputFeatureCursor.InsertFeature(outputFeatureBuffer);
        ReleaseComReferences(feature);
        feature = featureCursor.NextFeature();
    }
    outputFeatureCursor.Flush();
    if (!ReferenceEquals(workspaceEdit, null))
    {
        workspaceEdit.StopEditOperation();
        workspaceEdit.StopEditing(true); // This line causing the increase in memory but the same memory doesn't get released.
        ReleaseComReferences(workspaceEdit);
    }

    ReleaseComReferences(featureCursor);
    ReleaseComReferences(workspace);
    ReleaseComReferences(featureClass);
    ReleaseComReferences(outputFeatureCursor);
    ReleaseComReferences(outputFeatureBuffer);
    ReleaseComReferences(outputWorkspace);
    ReleaseComReferences(outputFeatureClass);
    ReleaseComReferences(workspaceFactory);
}

public void ReleaseComReferences(object refernce)
{
    if (refernce != null)
    {
        int refsLeft = 0;
        do
        {
           refsLeft = System.Runtime.InteropServices.Marshal.ReleaseComObject(refernce);
        }
        while (refsLeft > 0);
    }
}

Now, each time the CopyFeatures function is called, some memory doesn't get released, and the memory that is being used keeps on increasing. So any suggestion, how i can fix this memory leak issue? I have searched a lot on the internet but wasn't able to find a viable solution, every solution that i tried wasn't working, and still some memory wasn't being released.

Also i have checked with the copyfeatures tool and the memory issue doesn't occur, but the above code is just an excerpt from my original code, I also need to perform some logic and some checks on every feature, due to which I cannot use copyfeatures in this scenario.

Best Answer

I was able to fix this issue by starting and stopping of workspace edit session after the features have been inserted. In the above case, following will be the desired copyfeatures function which won't have any memory leak.

public void CopyFeatures(string srcFile, string srcDir, string outFile, string outDir)
{
    IWorkspaceFactory workspaceFactory = new ESRI.ArcGIS.DataSourcesFile.ShapefileWorkspaceFactory();
    IWorkspace workspace = workspaceFactory.OpenFromFile(srcDir, 0);        
    IFeatureClass featureClass = ((IFeatureWorkspace)workspace).OpenFeatureClass(srcFile);
    IFeatureCursor featureCursor = featureClass.Search(null, false);
    IFeature feature = featureCursor.NextFeature();

    IWorkspace outputWorkspace = workspaceFactory.OpenFromFile(outDir, 0);
    IFeatureClass outputFeatureClass = ((IFeatureWorkspace)outputWorkspace).CreateFeatureClass(outFile, featureClass.Fields, null, null, esriFeatureType.esriFTSimple, "Shape", "");

    IFeatureBuffer outputFeatureBuffer = outputFeatureClass.CreateFeatureBuffer();
    IFeatureCursor outputFeatureCursor = outputFeatureClass.Insert(true);

    while (feature != null)
    {
        for (int i = 0; i < outputFeatureBuffer.Fields.FieldCount; i++)
        {
            IField field = feature.Fields.Field[i];
            string myName = field.Name;
            if (field.Editable == true)
               outputFeatureBuffer.Value[outputFeatureBuffer.Fields.FindField(myName)] = feature.Value[feature.Fields.FindField(myName)];
        }

        outputFeatureCursor.InsertFeature(outputFeatureBuffer);
        ReleaseComReferences(feature);
        feature = featureCursor.NextFeature();
    }
    outputFeatureCursor.Flush();

    IWorkspaceEdit workspaceEdit = ((IDataset)outputFeatureClass).Workspace as IWorkspaceEdit;
    if (!workspaceEdit.IsBeingEdited())
    {
         workspaceEdit.StartEditing(false);
         workspaceEdit.StartEditOperation();
    }

    if (!ReferenceEquals(workspaceEdit, null))
    {
        workspaceEdit.StopEditOperation();
        workspaceEdit.StopEditing(true); // Now no memory leak.
        ReleaseComReferences(workspaceEdit);
    }

    ReleaseComReferences(featureCursor);
    ReleaseComReferences(workspace);
    ReleaseComReferences(featureClass);
    ReleaseComReferences(outputFeatureCursor);
    ReleaseComReferences(outputFeatureBuffer);
    ReleaseComReferences(outputWorkspace);
    ReleaseComReferences(outputFeatureClass);
    ReleaseComReferences(workspaceFactory);
}
Related Question