Releasing memory properly when using a BBS


Author
Message
Andria Jensen
Andria Jensen
StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)
Group: Forum Members
Posts: 336, Visits: 497
I have numerous DevExpress grids and tree list controls in my application which I am binding to BOs using BusinessBindingSource controls.  I have recently discovered that DevExpress does a very poor job of releasing memory and disposing of their own object properly.  I have a lot of memory leaks coming up in my app because of this.  Now, to the part where SF is involved...I have been running memory profilers which are showing that the grids, trees, etc are still linked to the BBS which is preventing them from being disposed of properly at garbage collection. 

My theory is that the BBS is somehow dynamically creating columns in the grid or tree at runtime, but not manually disposing of them when it's unloaded.  DevExpress basically expects you to dispose of everything, so I'm wondering if somehow the BBS is still linked to the DevExpress controls and preventing them from being released from memory correctly.  Is this a possibility?

I can open and close a test form I have created without filling the BO that is linked to the BBS, and it releases all memory correctly when the form is closed.  If I fill the BO when opening the form, it will not release all memory once closed.  Any ideas here?

Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K
My theory is that the BBS is somehow dynamically creating columns in the grid or tree at runtime, but not manually disposing of them when it's unloaded.  DevExpress basically expects you to dispose of everything, so I'm wondering if somehow the BBS is still linked to the DevExpress controls and preventing them from being released from memory correctly.  Is this a possibility?

No, sorry.  You have been around for a while and probably remember that we (MicroFour) were initially using DevExpress controls in our medical application and is why we initially created the DevExpress wrapper.  We wrote a single piece of our medical application and experienced massive memory leaks and very poor performance.  It became so bad that we could not release our product using DevExpress and that is when we wrote more SF controls and Themes got introduced.

The BBS follows .NET binding standards and does not create anything within the grid.  If the DevExpress grid is not releasing the binding, this is on the DevExpress side...period.  The BBS does nothing more than implement the IBindingList interface and then expose a unique BO with the strong-typed properties from the wrapped BO.  But if the BBS is properly managed, the Dispose should be picked up and cleaned up through the garbage collector.

As a side note here, we have hundreds of Custom BBS classes in our medical application and we have no memory leaks and we deal with massive amounts of data throughout the life of a session.  So I would never say that there is no possible way that the BBS may not be getting cleaned up due to an SF bug, but I will say that it is very unlikley.

I can open and close a test form I have created without filling the BO that is linked to the BBS, and it releases all memory correctly when the form is closed.  If I fill the BO when opening the form, it will not release all memory once closed.  Any ideas here?

Possibly.  Now this is generally more attributed to rendering issues, but there is a lot of logic that happens in the instantiation of objects as well as registering itself with the parent container or control as well as the native .NET collections )i.e. garbage collector).  You might wait until a handle is created by testing on the IsHandleCreated or override the OnLoad of the form and fill there.  If you are doing the Fill in a constructor the I could see this being more of an issue.  Finally, Fill from different locations to see where the GC finally recognizes the object.  For example, the Shown event, etc.  This is all going to be related to .NET and the GC versus the management of the BBS and BOs.

Andria Jensen
Andria Jensen
StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)
Group: Forum Members
Posts: 336, Visits: 497
I think I understand what you are saying...basically, depending on the area where you fill a BO it may or may not get registered with the collection that the GC uses to dispose of objects in memory during collection cycles.  Is that right? 

But, if I am manually disposing of the BO and the BBS in the FormClosed event, shouldn't this be enough no matter where it's being filled or instantiated? 

Also, what is the proper and recommended way to manage memory as far as StrataFrame objects go?  Should we be manually disposing of things when they are no longer in use or is it ok to leave that to the GC?

Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K
I think I understand what you are saying...basically, depending on the area where you fill a BO it may or may not get registered with the collection that the GC uses to dispose of objects in memory during collection cycles.  Is that right? 

Yes.

But, if I am manually disposing of the BO and the BBS in the FormClosed event, shouldn't this be enough no matter where it's being filled or instantiated? 

Not if something holds on to an event or an instance binding and will not release it.

Also, what is the proper and recommended way to manage memory as far as StrataFrame objects go?  Should we be manually disposing of things when they are no longer in use or is it ok to leave that to the GC?

If you drop an instance on the form, the Dispose should be intrinsically called as all BOs inplement the IDidposable interface.  If done in code, then manually Dispose of the object.

Andria Jensen
Andria Jensen
StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)
Group: Forum Members
Posts: 336, Visits: 497
I'm still tracking this down, but have come across a lot of places where I was not manually disposing of a BO when I instantiated in code.  I was not aware that the BO would not be collected automatically by the GC.  So, I am now going through my code and cleaning up everything I can find.  Which leads me to my question now, where is the appropriate place to dispose of the class level BOs I have created inside of another BO?  The dispose method is already overriden in the designer code, but I would think that would be the place to do it.  What is the best practice here?
Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K
You can place your code in the Dispose of that class.  Just place your code at the top of the Dispose :

If disposing Then
   myDefinedBO.Dispose()
End If

Andria Jensen
Andria Jensen
StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)
Group: Forum Members
Posts: 336, Visits: 497
But if it is the dispose of a BO, it is in the designer code which is regenerated with each partial.  Is this where you are referring to?

<System.Diagnostics.DebuggerNonUserCodeAttribute()> _
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
  If (disposing AndAlso (Not (Me.components) Is Nothing)) Then
    Me.components.Dispose()
 
End If

  MyBase.Dispose(disposing)

End Sub

 


Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K
From your post, I thought you were referring to a BBS instead of the BO.  Technically, in this example, they objects should dispose of themselves since the BOs implement IDisposable.  However, .NET isn't always good about managing this. 

In this particular example, I rarely manually dispose of the object.  And we have this type of code all over the place.  We have hundreds of instances where we have this type of code and it gets cleaned up.  When I was referring to in code, I was talking about as a local like this:

Dim lc As New MyBo()

'-- Do your stuff here

lc.Dispose()

However, it never hurts to manually Dispose() of objects if they are getting "hung up" due to the environment in which they are being used.  So in your case, I would manually Dispose() to see if memory gets cleaned up.  In this case, I would palce all of my logic in the BaseBO in which all of my BOs inherit.  Then this code would be implemented in a single location versus having to be re-written for each BO.  Also, using this approach will not be an issue with the partial class.

Andria Jensen
Andria Jensen
StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)StrataFrame User (416 reputation)
Group: Forum Members
Posts: 336, Visits: 497
I actually was referring to the instance you were talking about.  Basically something like this:

Public Class MyBO

  Private MyOtherBO as New BOType

  -----  subs, functions, whatever ----

End Class

Where does MyOtherBO get disposed of?  It's a BO instantiated as a class level variable, inside of another BO.  It should go in the dispose for MyBO, but that is being generated inside the Designer code and will get overwritten if I regenerate the partial.

Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K

Where does MyOtherBO get disposed of?  It's a BO instantiated as a class level variable, inside of another BO.  It should go in the dispose for MyBO, but that is being generated inside the Designer code and will get overwritten if I regenerate the partial.

That is what I was referring to when talking about the BaseBO.  All of your BOs should inherit from a BaseBO that inherits BusinessLayer.  This allows you to provide base level logic for this very type of thing without having to code it for each individual BO and at the risk of the Dispose being overwritten.

GO

Merge Selected

Merge into selected topic...



Merge into merge target...



Merge into a specific topic ID...




Similar Topics

Reading This Topic

Login

Explore
Messages
Mentions
Search