Releasing memory using Marshal.FinalReleaseComObject

4307
23
Jump to solution
03-07-2012 11:37 AM
USFS_AGOLAdministrator
New Contributor III
Hi all,

I know this is alot of code, but you have to see the whole thing understand the problem. The code below is doing a Reverse Eliminate of sorts by looping through a selected set of sliver polygons, doing a spatial selection to find out what polygons are touching the slivers, getting the 2nd largest polygon that touches the sliver, and merging the sliver to the second largest polygon by unioning them together, and deleting the original sliver polygon.

It works beautifully well, except it bombs out after processing ~900 slivers with a memory error. I've tried everything I can think of to release the memory, as you will see below. Can anyone see anywhere I can release more memory?

Try
     Using comReleaser As ESRI.ArcGIS.ADF.ComReleaser = New ESRI.ArcGIS.ADF.ComReleaser()
Dim pFeat As IFeature = Nothing
Dim pEnumFeat As IEnumFeature = CType(pMap.FeatureSelection, IEnumFeature)
'Dim pEnumFeat As IEnumFeature = CType(pFLayer.SelectionSet, IEnumFeature)
pEnumFeat.Reset()
Dim pFCur As IFeatureCursor = Nothing
Dim pSF As ISpatialFilter
pSF = New SpatialFilter
Dim pTopoOp As ITopologicalOperator
Dim pLargestAdj As IFeature = Nothing
Dim sliverFeat As IFeature = Nothing
sliverFeat = pEnumFeat.Next

Do Until sliverFeat Is Nothing
'this is really the smallest
'---------------------------------------------------------------------
pLargestAdj = GetLargestAdjacent(sliverFeat, True, pSF, pFCur, pFClass)
'---------------------------------------------------------------------

If Not pLargestAdj Is Nothing Then

pTopoOp = CType(pLargestAdj.ShapeCopy, ITopologicalOperator)
pLargestAdj.Shape = pTopoOp.Union(sliverFeat.ShapeCopy)

updateFeature(m_pFLayer.FeatureClass, pLargestAdj.OID, pLargestAdj.Shape)

sliverFeat.Delete()

Marshal.FinalReleaseComObject(sliverFeat)
Marshal.FinalReleaseComObject(pTopoOp)
Marshal.FinalReleaseComObject(pLargestAdj)

Else
Debug.Print("nothing adjacent to: " & sliverFeat.OID)
End If

nCurRecNo = nCurRecNo + 1
My.ArcMap.Application.StatusBar.Message(0) = nCurRecNo.ToString & "/" & n.ToString & " records complete."

Application.DoEvents()

comReleaser.ManageLifetime(sliverFeat)

sliverFeat = pEnumFeat.Next
Loop

'Stop editing and save the edits
pEditor.StopEditing(True)
Runtime.InteropServices.Marshal.FinalReleaseComObject(pLargestAdj)
End Using

Catch ex As Exception
MsgBox("Error: " & ex.StackTrace, , "RElimAddinPB_onClick")
End Try

---------------------------------------------------------------------------------------------------------------------------------------------
'!!!!!!!!!!!!!!!!!!!!!!!This function is where it bombs out after ~900 records!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Function GetLargestAdjacent(ByVal pFeat As IFeature, ByVal getSecondLargest As Boolean, ByVal pSF As ISpatialFilter, ByVal pFcur As IFeatureCursor, ByVal pFC As IFeatureClass) As IFeature

Try

pSF.Geometry = pFeat.Shape
pSF.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects

pFcur = pFC.Search(pSF, False)

If pFC.FeatureCount(pSF) < 3 Then 'This is set if there is only polygons on one side of the sliver
getSecondLargest = False
End If

Using comReleaser As ESRI.ArcGIS.ADF.ComReleaser = New ESRI.ArcGIS.ADF.ComReleaser()

Dim pFeat2 As IFeature = Nothing, pLargestFeat As IFeature = Nothing
comReleaser.ManageLifetime(pFeat2)
comReleaser.ManageLifetime(pFcur)
Dim dMaxArea As Double = 0
pFeat2 = pFcur.NextFeature

Do Until pFeat2 Is Nothing 'This loop executes everytime, no matter if there are slivers on both sides or not

If Not pFeat2 Is pFeat Then
If pLargestFeat Is Nothing Then
pLargestFeat = pFeat2

dMaxArea = GetArea(CType(pFeat2.Shape, IArea))

Else
If GetArea(CType(pFeat2.Shape, IArea)) > dMaxArea Then
pLargestFeat = pFeat2
dMaxArea = GetArea(CType(pFeat2.Shape, IArea))
Runtime.InteropServices.Marshal.FinalReleaseComObject(pLargestFeat)
Runtime.InteropServices.Marshal.FinalReleaseComObject(pFeat2)
End If
End If
End If

pFeat2 = pFcur.NextFeature
pFcur.Flush()

Loop

Marshal.ReleaseComObject(pFcur)
'comReleaser.Dispose()

If getSecondLargest Then 'This loop will execute only if there are polygons on both sides of the sliver
'pFCur = pFC.Search(pSF, False)
pFcur = m_pFLayer.FeatureClass.Search(pSF, False)

Dim pSecondLargestFeat As IFeature = Nothing
Dim dSecondMaxArea As Double = 0

pFeat2 = pFcur.NextFeature
Do Until pFeat2 Is Nothing
comReleaser.ManageLifetime(pFcur)
If Not pFeat2 Is pLargestFeat Then
If Not pFeat2 Is pFeat Then
If pSecondLargestFeat Is Nothing Then
pSecondLargestFeat = pFeat2
dSecondMaxArea = GetArea(CType(pFeat2.Shape, IArea))
Else
If GetArea(CType(pFeat2.Shape, IArea)) > dSecondMaxArea Then
pSecondLargestFeat = pFeat2
dSecondMaxArea = GetArea(CType(pFeat2.Shape, IArea))
End If
End If
End If
End If

pFeat2 = pFcur.NextFeature
pFcur.Flush()
Loop

pLargestFeat = pSecondLargestFeat

End If

Marshal.ReleaseComObject(pFcur)
GetLargestAdjacent = pLargestFeat
'comReleaser.Dispose()

End Using

Catch ex As Exception
MsgBox(ex.Message, , "Ex routine")
MsgBox(ex.StackTrace, , "Ex routine")
GetLargestAdjacent = Nothing
End Try


End Function

----------------------------------------------------------------------------------------------

Private Sub updateFeature(ByVal fc As IFeatureClass, ByVal oid As Integer, ByVal newGeom As IGeometry)
Dim queryFilter As IQueryFilter = New QueryFilter() With { _
.WhereClause = Convert.ToString(fc.OIDFieldName) & " = " & oid.ToString() _
}

Dim featureCursor As IFeatureCursor = fc.Update(queryFilter, False)
Dim featureToUpdate As IFeature = featureCursor.NextFeature()

featureToUpdate.Shape = newGeom
featureCursor.UpdateFeature(featureToUpdate)
Runtime.InteropServices.Marshal.ReleaseComObject(featureToUpdate)
featureCursor.Flush()
End Sub

--------------------------------------------------------------------------------------------------------------

Function GetArea(ByVal pArea As IArea) As Double
GetArea = pArea.Area
End Function
0 Kudos
1 Solution

Accepted Solutions
RichWawrzonek
Occasional Contributor
Rich,

I tried intantiating the cursor and filter in the GetLargest Adjacent function to begin with, it still had the same problem.


Was this before you added all the ComReleaser stuff? It seems weird that you are creating an object in the main loop and releasing it in a sub function. Maybe create the feature cursor object in GetLargestAdjacent() and then force garbage collection in the main loop using this code:
GC.Collect() GC.WaitForPendingFinalizers()


More information on the GC class here:
http://msdn.microsoft.com/en-us/library/system.gc.aspx

View solution in original post

0 Kudos
23 Replies
RichWawrzonek
Occasional Contributor
Are you getting the ArcMap 'Out of memory' error or something else?

I'm not sure why you are instantiating your feature cursor and spatial filter (pFCur, pSF) outside of the GetLargestAdjacent() function. They aren't used in the main loop. Try creating them in GetLargestAdjacent() and see if that helps. It's generally a bad idea to pass feature cursors around.
0 Kudos
NeilClemmons
Regular Contributor III
Could you edit this to use the CODE tags (the # button on the toolbar in the editing window) so that the code you posted is formatted correctly?
0 Kudos
sapnas
by
Occasional Contributor III
I remember having memory issue with Union method in 9.3. Have you tried commenting pTopoOp.Union(sliverFeat.ShapeCopy)? This might help in narrowing down the issue.
0 Kudos
USFS_AGOLAdministrator
New Contributor III
Here is the code properly formatted:


            Try
                Using comReleaser As ESRI.ArcGIS.ADF.ComReleaser = New ESRI.ArcGIS.ADF.ComReleaser()
                    Dim pFeat As IFeature = Nothing
                    Dim pEnumFeat As IEnumFeature = CType(pMap.FeatureSelection, IEnumFeature)
                    'Dim pEnumFeat As IEnumFeature = CType(pFLayer.SelectionSet, IEnumFeature)
                    pEnumFeat.Reset()
                    Dim pFCur As IFeatureCursor = Nothing
                    Dim pSF As ISpatialFilter
                    pSF = New SpatialFilter
                    Dim pTopoOp As ITopologicalOperator
                    Dim pLargestAdj As IFeature = Nothing
                    Dim sliverFeat As IFeature = Nothing
                    sliverFeat = pEnumFeat.Next

                    Do Until sliverFeat Is Nothing
                        'this is really the smallest
                        '---------------------------------------------------------------------
                        pLargestAdj = GetLargestAdjacent(sliverFeat, True, pSF, pFCur, pFClass)
                        '---------------------------------------------------------------------

                        If Not pLargestAdj Is Nothing Then

                            pTopoOp = CType(pLargestAdj.ShapeCopy, ITopologicalOperator)
                            pLargestAdj.Shape = pTopoOp.Union(sliverFeat.ShapeCopy)

                            updateFeature(m_pFLayer.FeatureClass, pLargestAdj.OID, pLargestAdj.Shape)

                            sliverFeat.Delete()

                            Marshal.FinalReleaseComObject(sliverFeat)
                            Marshal.FinalReleaseComObject(pTopoOp)
                            Marshal.FinalReleaseComObject(pLargestAdj)

                        Else
                            Debug.Print("nothing adjacent to: " & sliverFeat.OID)
                        End If
                        nCurRecNo = nCurRecNo + 1
                        My.ArcMap.Application.StatusBar.Message(0) = nCurRecNo.ToString & "/" & n.ToString & " records complete."
                        Application.DoEvents()
                        comReleaser.ManageLifetime(sliverFeat)
                        sliverFeat = pEnumFeat.Next
                    Loop

                    'Stop editing and save the edits
                    pEditor.StopEditing(True)
                    Runtime.InteropServices.Marshal.FinalReleaseComObject(pLargestAdj)
                End Using

            Catch ex As Exception
                MsgBox("Error: " & ex.StackTrace, , "RElimAddinPB_onClick")
            End Try

            m_gdbPath = ""

            'refresh the selectionset on screen
            Dim pActiveView As IActiveView
            pActiveView = CType(pMap, IActiveView)
            pMxDoc.CurrentContentsView.Refresh(Nothing)
            pActiveView.Refresh()

            'Let the user know it completed successfully
            MsgBox("Complete")
            'Show the user how long it took to process
            Dim tElapsed As TimeSpan = DateTime.Now.Subtract(tStartTime)
            MsgBox(nCurRecNo.ToString + " records in: " + tElapsed.Hours.ToString + " hours " + tElapsed.Minutes.ToString + " minutes " + tElapsed.Seconds.ToString + " seconds.")
            m_pFLayer = Nothing

        Catch ex As Exception
            MsgBox(ex.StackTrace)
            MsgBox(ex.Message)

        End Try
    End Sub
    Function GetLargestAdjacent(ByVal pFeat As IFeature, ByVal getSecondLargest As Boolean, ByVal pSF As ISpatialFilter, ByVal pFcur As IFeatureCursor, ByVal pFC As IFeatureClass) As IFeature
        'MsgBox("in get largest adjacent")
        Try

            pSF.Geometry = pFeat.Shape
            pSF.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects

            'pFcur = pFC.Search(pSF, False)
            pFcur = pFC.Update(pSF, False)
            'If m_pFLayer.FeatureClass.FeatureCount(pSF) < 3 Then
            '    getSecondLargest = False
            'End If

            If pFC.FeatureCount(pSF) < 3 Then
                getSecondLargest = False
            End If
           
            Using comReleaser As ESRI.ArcGIS.ADF.ComReleaser = New ESRI.ArcGIS.ADF.ComReleaser()

                Dim pFeat2 As IFeature = Nothing, pLargestFeat As IFeature = Nothing
                comReleaser.ManageLifetime(pFeat2)
                comReleaser.ManageLifetime(pFcur)
                Dim dMaxArea As Double = 0
                pFeat2 = pFcur.NextFeature

                Do Until pFeat2 Is Nothing

                    If Not pFeat2 Is pFeat Then
                        If pLargestFeat Is Nothing Then
                            pLargestFeat = pFeat2

                            dMaxArea = GetArea(CType(pFeat2.Shape, IArea))
                            pFcur.Flush()
                            'Runtime.InteropServices.Marshal.FinalReleaseComObject(pLargestFeat)
                        Else
                            If GetArea(CType(pFeat2.Shape, IArea)) > dMaxArea Then
                                pLargestFeat = pFeat2
                                dMaxArea = GetArea(CType(pFeat2.Shape, IArea))
                                Runtime.InteropServices.Marshal.FinalReleaseComObject(pLargestFeat)
                                Runtime.InteropServices.Marshal.FinalReleaseComObject(pFeat2)
                            End If
                        End If
                    End If

                    pFcur.Flush()
                    pFeat2 = pFcur.NextFeature


                Loop

                Marshal.ReleaseComObject(pFcur)
                'comReleaser.Dispose()

                If getSecondLargest Then
                    'pFCur = pFC.Search(pSF, False)
                    'pFcur = m_pFLayer.FeatureClass.Search(pSF, False)
                    pFcur = m_pFLayer.FeatureClass.Update(pSF, False)
                    Dim pSecondLargestFeat As IFeature = Nothing
                    Dim dSecondMaxArea As Double = 0

                    pFeat2 = pFcur.NextFeature
                    Do Until pFeat2 Is Nothing
                        comReleaser.ManageLifetime(pFcur)
                        If Not pFeat2 Is pLargestFeat Then
                            If Not pFeat2 Is pFeat Then
                                If pSecondLargestFeat Is Nothing Then
                                    pSecondLargestFeat = pFeat2
                                    dSecondMaxArea = GetArea(CType(pFeat2.Shape, IArea))
                                Else
                                    If GetArea(CType(pFeat2.Shape, IArea)) > dSecondMaxArea Then
                                        pSecondLargestFeat = pFeat2
                                        dSecondMaxArea = GetArea(CType(pFeat2.Shape, IArea))
                                    End If
                                End If
                            End If
                        End If

                        pFeat2 = pFcur.NextFeature
                        pFcur.Flush()
                    Loop

                    pLargestFeat = pSecondLargestFeat

                End If

                Marshal.ReleaseComObject(pFcur)
                GetLargestAdjacent = pLargestFeat
                'comReleaser.Dispose()

            End Using




        Catch ex As Exception
            MsgBox(ex.Message, , "Ex routine")
            MsgBox(ex.StackTrace, , "Ex routine")
            GetLargestAdjacent = Nothing
        End Try


    End Function
    Private Sub updateFeature(ByVal fc As IFeatureClass, ByVal oid As Integer, ByVal newGeom As IGeometry)
        Dim queryFilter As IQueryFilter = New QueryFilter() With { _
          .WhereClause = Convert.ToString(fc.OIDFieldName) & " = " & oid.ToString() _
        }

        Dim featureCursor As IFeatureCursor = fc.Update(queryFilter, False)
        Dim featureToUpdate As IFeature = featureCursor.NextFeature()
        featureToUpdate.Shape = newGeom
        featureCursor.UpdateFeature(featureToUpdate)
        Runtime.InteropServices.Marshal.ReleaseComObject(featureToUpdate)
        featureCursor.Flush()
    End Sub
0 Kudos
USFS_AGOLAdministrator
New Contributor III
Are you getting the ArcMap 'Out of memory' error or something else?

I'm not sure why you are instantiating your feature cursor and spatial filter (pFCur, pSF) outside of the GetLargestAdjacent() function. They aren't used in the main loop. Try creating them in GetLargestAdjacent() and see if that helps. It's generally a bad idea to pass feature cursors around.


Rich,

I tried intantiating the cursor and filter in the GetLargest Adjacent function to begin with, it still had the same problem.
0 Kudos
USFS_AGOLAdministrator
New Contributor III
I remember having memory issue with Union method in 9.3. Have you tried commenting pTopoOp.Union(sliverFeat.ShapeCopy)? This might help in narrowing down the issue.


When I commented this out, it ran much faster, but still errored out with a message:

"There is not enough memory" 

But I will try commenting things out, to see what is causing it.  Thanks for the suggestion.
0 Kudos
RichWawrzonek
Occasional Contributor
Rich,

I tried intantiating the cursor and filter in the GetLargest Adjacent function to begin with, it still had the same problem.


Was this before you added all the ComReleaser stuff? It seems weird that you are creating an object in the main loop and releasing it in a sub function. Maybe create the feature cursor object in GetLargestAdjacent() and then force garbage collection in the main loop using this code:
GC.Collect() GC.WaitForPendingFinalizers()


More information on the GC class here:
http://msdn.microsoft.com/en-us/library/system.gc.aspx
0 Kudos
NeilClemmons
Regular Contributor III
I would get rid of using the ComReleaser altogether.  Here is the proper way to get a cursor and loop through it as well as clean up the objects that it uses:

Dim featureCursor As IFeatureCursor = featureClass.Search(queryFilter, False)
Dim feature As IFeature = featureCursor.NextFeature
Do While feature IsNot Nothing
    ' do something with the feature
    FinalReleaseComObject(feature) ' release the feature before setting it to the next feature in the cursor
    feature = featureCursor.NextFeature
Loop
FinalReleaseComObject(featureCursor) ' release the cursor


Look through your code and make sure you're releasing every cursor as soon as you're done with it and that you're releasing all feature references as soon as you're done with them (including those used in loops as shown above).  This is most likely where you're getting your error from.

One of your functions returns an IFeature reference.  I would change this to return the feature's geometry because that's what you're actually needing from the feature.

Post your updated code if you're still having problems.
0 Kudos
sapnas
by
Occasional Contributor III
Have you tried trouble shooting the issue  by  monitoring the memory usage in taskmgr while stepping through each statement of your code?
0 Kudos