3

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.

  • What version of ArcGIS are you using? – Vince Sep 30 '14 at 10:44
  • I have ArcGIS 10.1. – Omer Kahoot Sep 30 '14 at 10:58
  • Please answer questions in comments by clarifying the Question, so that those who would answer don't have to sift through comments for critical information. Have you applied Service Pack 1? It seems more likely that you have used an option that requires more effective cleanup than that the API itself has a leak. I'm not a C# guy, but I would double-check all the methods with Boolean parameters. – Vince Sep 30 '14 at 11:15
  • Just an idea, if this is not solved, why not call the Copy Features GeoProcessing tool instead? I assume that will release its memory in an appropriate manner? – Hornbydd Sep 30 '14 at 11:57
  • @Hornbydd, thank you for the suggestion, yeah I have also worked with the CopyFeatures GeoProcessing tool, and yes it is much better, but actually the above code is just an excerpt from my original code, and originally, I need to perform different logic and different checks on every feature depending upon the values in their fields, due to which I cannot use CopyFeatures. – Omer Kahoot Oct 1 '14 at 5:39
2

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);
}
-1

IWorkspaceEdit interface is only be in use when working with geodatabase. Your case is shapefile - I don't understand why using methods Start_stop editing helps to solve memory liking problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.