AnsweredAssumed Answered

Releasing memory using Marshal.FinalReleaseComObject

Question asked by USForestServiceAdmin on Mar 7, 2012
Latest reply on Mar 9, 2012 by USForestServiceAdmin
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

Outcomes