My .net application does some heavy string loading/manipulation and unfortunately the memory consumption keeps rising and rising and when looking at it with a profiler I see alot of unreleased string instances. Now at one point of time or another I do need all objects t hat do have these string fields, but once done, I could get rid of e.g. the half of it and I Dispose() and set the instances to null, but the Garbage Collector does not to pick that up.. they remain in memory (even after half an hour after disposing etc).
Now how do I get properly rid of unneeded strings/object instances in order to release them?
They are nowhere referenced anymore (afaik) but e.g. aspose’s memory profiler says their distance to the gc’s root is ‘3’?
Update: The original strings are coming from an interop instance. Is it possible that those are causing the leaks?
As in.. assigning
myClass.StringProperty = interopInstance.Description.Text;
.. does my .StringProperty still have a reference to that interop one and therefore ‘leaking’/keep the interopInstance uncollected & not properly released/unmarshaled?
Setting a private field to
nullcan be useful when the class containing that field will still be used. It will allow the referenced object to be collected. However, when that instance of that private field itself is unreferenced, so will the object it references. In other words, it’s not useful to null out private fields on an object that gets unreferenced soon.I think you don’t have an application leak. Perhaps you are creating strings that are stored in the large object heap (LOH). Objects are stored in the LOH when greater or equal than 85000 bytes (with 42492 characters or more). The LOH is only collected when a full garbage collect (gen 2) happens. Therefore, since you don’t seem to have any
OutOfMemoryExceptions, I don’t think there’s a leak. Your application simply doesn’t run out of memory and the GC just doesn’t collect Gen2.You can check this by calling
GC.Collect(). This would remove all unused large objects.So while there probably is no leak in your application, the memory footprint can be undesirable big. Especially when you’re writing a desktop application that isn’t the only application asking for memory. Besides this, a big pile of memory could also cause performance problems, because the GC has to run more often.
Perhaps it is possible to refactor your code in a way that it uses less memory. Using
StringBuilderobjects for instance (if you’re not doing that already). Or perhaps even cachingStringBuilderobjects in a pool and reusing them instead of creating a new one. Especially when setting the Capacity property when using an instance you got from the pool. This could be especially useful, because LOH tends to get fragmented easily, which can causeOutOfMemoryExceptionsto occur. This is btw only a problem on 32bit systems, because 64bit systems have almost unlimited virtual address space. 64bit will get more and more mainstream in the coming years, and I believe Microsoft hasn’t invested into fixing this problem for 32bit versions of the CLR, because of that.Update:
In the case of interop, strings are serialized and deserialized. A string is sent over as byte array so in general there is no change of it keeping references. However, each time you fetch a string from interop a new byte array will be created and in .NET that byte[] is copied into a string. This will double the amount of memory used.