Hi,
Very recently my application that uses an UltraTree started consuming vast resources. I have found that a single node object when part of a heirarchy will consume upwards of 50KB.
Furthermore if I add the root node object to a tree control's nodes collection, clearing the tree's node collection (using nodes.clear() ) does not release the references to the nodes. This means if you build a tree, then clear it's nodes and try to rebuild it, you will be holding two full trees in memory. At upwards of 50KB per node, this will bring a system to it's knees when you are working with trees containing thousands of nodes.
The same project used to consume far less resources prior to upgrading to 2011.1. Can you please advise?
I have attached a simple project that procedurally generates a tree as an example (using 2011.2 where the problem still exists).
Thanks.
If I understand you correctly, it seems like the problem all along has not had anything to do with the new versions of the controls, but rather was a function of the operating system. Is that right?Are you essentially getting the same results from v9.1 and v11.2 if you run them on the same machine?
I took a look at your new sample and this seems like it will be a much better test of memory usage. Personally, I wouldn't use randomly-generated data and random images, but it's probably not a big deal.
Anyway, I'm running Windows 7 64-bit and I ran your sample through Ants. I started profiling and when the form comes up, I take a snapshot.
Total size of objects in snapshot 1: 375.1KB
I then push the button to populate the tree and I get this:
Total size of objects in baseline snapshot snapshot 1: 375.1KB
Total size of objects in snapshot 2: 17.69 MB
Difference between snaphot 2 and snapshot 1: +17.33 MB
So in this new sample, it's a little more memory than in the previous one, but still only 17 MB.
I really have no idea why the same sample application would be using 700 MB, or even 98 MB on your machine.
But I can tell you that there is nothing specific to the controls that does anything any differently on a 32-bit machine vs. a 64-bit machine. So if the memory usage is different and you are certain that you are using exactly the same sample application, the same version of the Infragistics assemblies, and the same version of the DotNet framework, then the only explanation I can think of is that it's the O/S.
BTW, I'm using Ants Memory Profiler 7.0.0.731, which I think is the latest version (or close to it). Perhaps there is something else going on in the version of Ants you have. If you want to post the results of your Ants profiling here, I will be happy to take a look at it, but I'm not sure what good that will do.
Hi Mike,
Since the platform the application is running on was different for the different versions, I decided we need to eliminate that variable as well. I copied the v9.1 assemblies to the x64 server I built the VS2010 version on, and ran the VS2008 version there.
To my surprise the same 2008 version that only uses 98MB on Server 2003 (32-bit) uses nearly 700MB on Server 2008 r2 (64-bit)! I would expect a small increase in the amount of memory used when moving from 32 to 64-bit, but a near 7x increase?
Is this to be expected? How should we proceed?
v9.1/VS2008 Version here
Thank you for that very robust response. Let us for now disregard my comment of a possible memory leak so we can remove the esoteric nature of the GC from the equation. it may very well be that the GC is tricking me into thinking there is a leak where there isn't. The sample application I wrote does not attempt to force the GC process, so isn't geared toward highlighting any memory leaks.
I apologize if my applications were different. I worked on a couple iterations, and it seems that I sent you the wrong version of the first (VS2010) application.
Since it seems we are having very different results, I rewrote the sample application to eliminate ambiguities. When clicking the button in the application it now will clear the tree, generate a node hierarchy and then add that to the tree control's node collection. I changed the manner that I get image resources to be the standard My.Resources method. I also standardized both the applications to target .NET Framework 3.5.
I have no idea what you are looking at to indicate a memory increase of only ~12MB when loading over 10K nodes. What platform are you running the applications on? When using ANTS to profile the memory, I don't get a different picture from that painted by Task Manager, just more detailed. The v11.2 application built in VS2010 uses 677MB when the tree is loaded with 13013 nodes (run on Windows Server 2008 r2 x64), meanwhile the v9.1 application built in VS2008 uses 98MB when the tree is loaded with the same 13013 nodes (run on Windows Server 2003 SP2 x86)
I have attached the cleaner versions of the applications here.
Comparing these two applications is not a valid comparison for a number of reasons.
For one thing, the randomness is going to skew the results. But more importantly, the code in these samples is completely different. In the first sample, you are not even adding the nodes into the tree, you are just creating nodes in code and letting them go out of scope. In the second sample, you add these nodes into the tree and then clear the tree, but not until after you create a whole new set of nodes that are not in the tree.
So this whole sample application is going to be very confusing and difficult to work with in terms of finding any kind of memory issues.
Also, you seem to be under some misconceptions about how memory management and the GarbageCollector work.If your application is ultimately crashing because of an OutOfMemory exception, then something is probably using more and more memory.
But you cannot assume that the GarbageCollector is being called to collect unused memory every time your application requests more - that's not how it works. When the GC is called is completely arbitrary and you cannot assume when it will occur unless you explicitly invoke it yourself.
If you create a bunch of tree nodes, as in your first sample, and then you create a bunch more and the memory usage of your application goes up (the first set of nodes are not released), then that does not necessarily indicate a problem. You cannot just assume that the GC was (or should have been) called at that point. The proper way to do a test like this would be to make sure that the GC is called. Something like this will do it:
GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();
GC.Collect();
GC.WaitForPendingFinalizers();
As a general rule, if you create an object, you are responsible for disposing for that object. If you create a bunch of nodes and those nodes are never added to a Tree, then there's no way those nodes can possibly know when they should be disposed. So it would not be surprising if the first sample you posted here had a memory leak - although I am not sure that is, in fact, the case.
My understanding is that the GC should be called whenever an application asks for more memory than is apparently available, so it should avoid OutOfMemoryExceptions whenever possible.
In your second sample, where you are adding the nodes to the tree, it's something of a gray area whether or not the tree should dispose those nodes when they are removed from the tree. After all - you could very well be holding a reference to those nodes in a variable. So if removing them from the tree disposes them and you try to access those nodes you are still holding on to, your application would crash with an exception.
I took a quick look at the tree's source code and it does not look like the tree is actually disposing of the nodes that are removed, but I also don't see anything that should be holding on to the node once it is removed from the tree (or if it was never added to a tree).
Anyway... I tried running your new sample through Ants. I took an initial memory snapshot and then clicked the button and took another one. The memory usage (with v9.1) goes up by about 11MB. Clicking the button again increased the memory usage by about another 2MB. After that, the memory usage stays about the same.The biggest increase here seems to be from the UnmanagedMemoryStream class. I suspect this has something to do with the way you are retrieving your image resources.
I then tried the same experiment with v 11.2 of the tree.The first time I click the button, the memory usage goes up by about 12MB. On the second and subsequent clicks, the memory usage does not change significantly. If anything, it's going up even less than in the v9.1 version.
BTW... while the disposal of the nodes is something of a gray area, the disposal of the images is not. Your code creates these images and you are responsible for disposing them when they are no longer needed. There is no way the tree can make the assumption that just because the node is no longer needed that the image is no longer needed, either. The tree cannot dispose these images for you, you need to do it.
So I'm not seeing anything here that looks like a memory leak or any increase in the amount of memory used by the tree nodes.