I am working on a .NET application for processing geographic data that uses ESRI's ArcObjects COM library via ESRI's own .NET interop assemblies.
When running in production, the process can crash during some operations due to reaching the 2GB per-process memory limit. (ArcObjects is a 32-bit library.) This is because some of the processing steps can create many temporary ArcObjects geometry objects. It will leak memory and eventually run out of memory despite manually releasing these objects using FinalReleaseComObject
and associated helper methods. However, I can force the GC to release the memory by calling WaitForPendingFinalizers
, and calling it regularly along with GC.Collect
and FinalReleaseComObject
keeps the memory usage under control. Otherwise, many objects remain in memory until the process exits (normally or abnormally).
First question: why isn't the memory held by the ArcObjects COM objects released immediately? Or, why does the GC allow the process to crash instead of finalizing the released COM objects and reclaiming the memory before it crashes?
The application runs in production on Windows 2008 64-bit, while I develop using Windows 7 32-bit. I can get the process to crash on the production boxes, but not on my development box. I thought that this may have been because locally I usually run in Visual Studio with a Debug build, but I have also tried it without the debugger (Start Without Debugging) using a Release build but even then it didn't use anywhere near as much memory as in production and won't crash.
Second question: Why?
EDIT: In my previous experiments, I worked out that GC.Collect
by itself is not sufficient, even though I was calling it explicitly. I have a utility method that calls GC.Collect
followed by GC.WaitForPendingFinalizers
and calling it after every algorithm iteration keeps memory usage down.