开发者

Application leaking Strings?

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 afte开发者_如何学Pythonr 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 null can 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 StringBuilder objects for instance (if you're not doing that already). Or perhaps even caching StringBuilder objects 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 cause OutOfMemoryExceptions to 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.


Just taking a punt on this but are you concatenating a lot of strings? If so are you using the '+' operator to do so? A string is immutable, meaning that you could be creating a new string object in memory every time you work on it.

If you are concatenating strings you should consider using a StringBuilder object (if you are not doing so already) or even the String.Concat() method. This could be the problem, especially if you are concatenating strings in a loop at any point.


I've been working on a system for transmitting data between many terminals. These terminals generate Text Data (in XML) that is then Compressed and transmitted to other terminals. Originally we experienced the exact same issue you are with the application using more and more and more Ram and eventually running out of memory.. The speed at which it ran out was exponentially faster the more terminals that were connected to it.

Performance of this system was not the most important feature, but longterm uptime was.

After trawling through with profilers to find where our memory was disappearing we found that our strings ended up in LOH if there was anything substantial in them.

I know it's controversial and many people say don't force GC.Collect but i've also found other sites eg Rico Mariani that say if you have specific needs and you are sure that your objects end up in LOH then go ahead and do it, just remember that GC.Collect will impact performance.

The good news was that once we added this to the string processing area of the program we stay on about the same ram usage for the entire life of the application, and some of the systems that we've got this running have uptimes >60days.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜