We have a C++ library (No MFC, No ATL) that provides some core functionality to our .NET application. The C++ DLL is used by SWIG to generate a C# assembly that can be used to access its classes/methods using PInvoke. This C# assembly is used in our .NET application to use the functionality inside C++ DLL.
The problem is related to memory leaks. In our .NET application, I have a loop in my .NET code that creates thousands of instances of a particular class from the C++ DLL. The loop keeps slowing down as it creates instances but if I call GC.Collect() inside the loop (which I know is not recommended), the processing becomes faster. Why is this? Calling Dispose() on the types does not have any affect on the speed. I was expecting a decrease in program speed on using GC.Collect() but it’s just the opposite.
Each class that SWIG generates has a ~destructor which calls Dispose(). Every Dispose method has a lock(this) around the statements that make calls to dispose unmanaged memory. Finally it calls GC.SuppressFinalize. We also see AccessViolationException sporadically in Release builds. Any help will be appreciated.
Some types of object can clean up after themselves (via
Finalize) if they are abandoned without being disposed, but can be costly to keep around until the finalizer gets around to them; one example within the Framework is the enumerator returned byMicrosoft.VisualBasic.Collection.GetEnumerator(). Each call toGetEnumerator()will attach an object wrapped by the new enumerator object to various private update events managed by the collection’ when the enumerator isDisposed, it will unsubscribe its events. IfGetEnumerator()is called many times (e.g. many thousands or millions) without the enumerators being disposed and without an intervening garbage collection, the collection will get slower and slower (hundreds or thousands of times slower than normal) as the event subscription list keeps growing. Once a garbage-collection occurs, however, any abandoned enumerators’Finalizemethods will clean up their subscriptions, and things will start working decently again.I know you’ve said that you’re calling
Dispose, but I have a suspicion that something is creating anIDisposableobject instance and not callingDisposeon it. IfIDisposableclassFoocreates and owns an instance ofIDisposableclassBar, butFoodoesn’tDisposethat instance within its ownDisposeimplementation, callingDisposeon an instance ofFoowon’t clean up theBar. Once the instance ofFoois abandoned, whether or not it has beenDisposed, itsBarwill end up being abandoned without disposal.