There appears to be a memory leak in CSLA when used in conjunction with Static objects.
You can see in the attached project the exact code, and it is VERY easy to see the problem using Ants Profiler, but the gist of the problem is this.
If you have a BLB, or a RLB collection, that you populate with plain jane simple objects of the correct type, when those lists go out of scope, all of the objects and the list go out of scope and unload correctly. UNLESS, you add one or more static objects of the same type.
So, I can add 200,000 objects to my list, and add ONE static object to that same list, and it will end up keeping all 200,000 objects, the list, and my static object in memory...it appears forever.
We are using the static object to represent "non data driven" constant objects...like objects to represent **ALL** in a combobox, or an Empty line in a combobox....or a million other reasons that you may need to add the same item to every one of your lists of that particular type.
The sample program has 4 different categories of load
Loading a CSLA with many objects, and a single static object (Leak)
Loading a CSLA with many objects, and no static objects (No Leak)
Loading a list inherting from generic List<> with many objects, and a single static object (No Leak)
Loading a list inherting from generic List<> with many objects, and no static objects (No Leak)
Loading an object with an embedded generic List<> with many objects, and a single static object (No Leak)
Loading an object with an embedded generic List<> with many objects, and no static objects (No Leak)
Loading a LOCAL RLB variable with many objects, and a single static object (Leak)
Loading a LOCAL object inheriting from generic List<> with many objects, and a single static object (No Leak)
Loading a LOCAL object with an embedded generic List<> with many objects, and a single static object (No Leak)
One note, you need to hit the release button to be able to identify that the leak exists. This button sets the form level variables = null
Also, if you don't have Ants, you can see the memory grow continuously by just keep clicking on the local CSLA button. Since this is a local variable, it loads up (and leaks) a new copy of the variable everytime it is clicked. I added alot of rows in this method so you could easily see the growth
I would really appreciate it if Rocky or one of his main experts could look at the sample program and give me your thoughts...
I don't think Csla supports what you're trying to do. An object should have one parent, not be shared across multiple parents / root objects. I'd just have an instance with a special state to indicate its the "All" or "Not Selected" value.
Well, it is pretty clear it doesn't support it At least not correctly...
But the real question is why? What is CSLA doing to these objects that a normal list wouldn't do, and more specifically what actions are being taken by CSLA that causes this to break when it works just find adding to a normal list?
I suspect it has to do with the additional events that the parent/children use within CSLA that you don't find in a normal List<>, but I do not know.
Further, can you not add the same object to two different lists? It is just another reference to the same object...Is your statement about only having one parent a quantitative statement that Rocky has made clear about the framework, or is it just your opinion based on personal preference and experience? (not trying to flame here, just trying to get more information). I can think of MANY scenarios where it would be useful to track an object as an item in more than one list...
I think, but I could be wrong, that some of Rocky's own implementation of LINQ for his CSLA objects does specifically this same type of thing.
It is pretty easy to create a workaround for my scenario, but the ease of having a workaround wasn't really my focus...
Well, when I said not supported I meant "its invalid to use Csla objects like that."
You may be able to work around it, as Rocky suggests might be possible in that post... but I would doubt any effort would be put into supporting this scenario.
Personally I'd just create the "special" instance each time the list is generated. Its just one object, and its relatively cheap (esp. if you're going to have 20,000 other objects).. and you won't have to do special hackery.
The issue may also have to do with the object being static and not with it being in multiple lists.
I believe BLB hooks events for each of the objects in the list so it can listen for property changes. So, I think this effectively means that the static object is holding a reference to the list (by virtual of the event handler). This means the list won't ever be garbage collected.
You have to be careful with static objects with regards to events. Hooking a static event can have similar effects.
True... but its Csla doing the event hooking in this case, so the only official solution would have to be included in Csla.
You were right on the money about the events being the culprit. A colleague of mine modified my test project and simply subscribed to an event on the objects being created.
It now has the same leak that CSLA exhibits for the same scenario.
Good stuff. Learned something today.
You may want to look into the ExtendedBindingList<T> class. There you will find the OnAddEventHooks and OnRemoveEventHooks virtual functions.
What you may be able to do is to inherit from BusinessListBase and then override those two methods and do an implementation like:
if (!object.ReferenceEquals(item, constantObject))
This is all untested so I am not 100% sure this will do the trick, not to mention that I rather go for what Andy suggested, I personally don’t like changing the default behavior of the CSLA unless its absolutely necessary.
I researched this further, and yet another wrinkle is that BusinessBase objects also hold a reference to their parent list in their _parent member. So, this will also trip you up with static objects being added to a BusinessListBase class even if you take care of the event linkage.
I think you should be able to simply set the static value to null (constantObject) and recreate it (brand new one).
Once you release the static reference the object will stop being a garbage collector root object (static) and the garbage collector should be able to collect it and in turn collect the rest of the other objects.
Cheese but perhaps a workaround? I would't do this myself.
I'm not entirely sure you can resolve the issue. BindingList<T> and ObservableCollection<T> (both Microsoft base classes) hook the PropertyChanged events of objects contained in those list types.
To avoid using them, you have to give up data binding and use a more primitive list type.
Oh, and I believe Linq to Csla is only creating a view over the collection.. not actually adding the same instance to a new collection.
Copyright (c) Marimer LLC