Leaking Unmanaged Heap Memory:
- Interoperating with unmanaged code
- Aborted Finalizers
- Dynamic Code Generation Leaks
- XmlSerializer Leaks
Problem: "Using C-style DLLS that use P/Invoke and COM objects through COM interop. The Garbage Collector is unaware of unmanaged memory".
Solution: "Step through the code and examine memory usage before and after the unmanaged call to verify that the memory is reclaimed."
Problem: "An objects finalizer does not get called and it contains code to clean up unmanaged memory allocated by the object".
Solution: "In .Net 1.x the only solution was to tear down the process and start again. The .Net Framework 2.0 introduces critical finalizers, which indicate that a finalizer will be cleaning up unmanaged resources and must be given a chance to run during AppDomain teardown."
Problem: "Sometimes code needs to be generated dynamically... dynamic assemly must be regenerated. The old assembly will no longer be used, but there is no way to evict it from memory."
Solution: "Check if you are regenerat[ing] code". You could either "load the generated MSIL into a child AppDomain. The child AppDomain can be unloaded when the generated code changes and a new one spun up to host the updated MSIL." Or, in 2.0 you can use DynamicMethod.Invoke.
Problem: "XMLSerializer caches the temporary assemblies on a per-type basis" and when changing the root name within the XML by overloading the XMLSerializer constructor which doesn't cache.
Solution: Use XMLRootAttribute instead.
Leaking Managed Heap Memory
- Large Obect Heap Fragmentation
- Unneeded Rooted References
- Midlife Crisis
Problem: An object is 85,000 bytes or larger and allocated on the large object heap. "Unlike the rest of the managed heap, the Large Obect Heap is not compacted due to the cost of moving the large object. So as large objects are allocated, freed and cleanded up, gaps will appear." Which result in more memory usage then needed.
Solution: Try examining "how the application uses memory and specifically the types of objects that are on the large object heap using tools like CLRProfiler". Try to reduce the reliance on the LOH.
Problem/Solution: Forgetting to Null out rooted references, which prevents the GC from freeing up memory.
Problem: "A midlife crisis [...] is the overuse of managed heap memory and excessive amounts of processor time spent in the GC". An object lives to Gen1 or Gen2 and dies shortly afterward.
Solution: Beware of using finalizers in managed code. Use finalizers if there is a reference to unmanaged code. If using IDisposable, "implement the Dispose pattern to allow users of the object to clean up the resources and avoid finalization". Also don't hold onto objects before making a query to the database or a webservice.