none
Class is not being released from memory RRS feed

  • Question

  • I'm having trouble with a C# winforms app, in that some users are complaining of an "OutOfMemoryException". I believe I have tracked it down to reports, or rather how I'm calling them.

    Each report in this application has its own class to manage it. To run a report, the manager class is declared, and then run, with any necessary parameters. An example of how it might be called is as follows:

            private void PrintInventoryLevelsReportX()
            {
                ReportMngt.InventoryLevelReportMngt reportMngt = new DecEzy.ReportMngt.InventoryLevelReportMngt();
                reportMngt.Print(BrandFilterID);
            }

    According to my limited knowledge of how memory is managed in .NET applications, I would have thought that as soon as the PrintInventoryLevelsReportX() method is complete,  then the report manager class (in this case InventoryLevelReportMngt) is removed from memory. According to the memory profiler utility I'm using, however, this is not the case.

    As shown in the attached image (a screenshot from dotTrace) of the incoming referneces, it seems to be linked to the event of a button (although I'm not sure if I am reading it correctly). This would kind of be right, as in the middle of the InventoryLevelReportMngt class, it calls a form as dialog, to get confirmation from the user that  they wish to print.

    So, my question is, how do I stop this? How do I ensure that the report manager class gets removed from memory, rather than staying in memory forever like it is now?

    Thanks.

    Friday, March 30, 2012 12:08 PM

Answers

  • hi,

    you should dispose of objects that implement the IDisposable interface.

    You can easily do so by using the 'using' syntax:

     private void PrintInventoryLevelsReportX()
            {
                using (ReportMngt.InventoryLevelReportMngt reportMngt = new DecEzy.ReportMngt.InventoryLevelReportMngt())
                {
                reportMngt.Print(BrandFilterID);
                }
            }

    This works if ReportMngt.InventoryLevelReportMngt implements IDisposable (it should).

    The 'using' is equivalent to using a try catch, with the object being disposed in the finally clause.

    If InventoryLevelReportMngt is a self brewed class, implement IDisposable, and in there, dispose of all the IDisposable objects it uses.


    Regards, Nico

    • Proposed as answer by Konrad Neitzel Friday, March 30, 2012 12:34 PM
    • Marked as answer by fweeee Wednesday, April 4, 2012 4:42 AM
    Friday, March 30, 2012 12:16 PM

All replies

  • hi,

    you should dispose of objects that implement the IDisposable interface.

    You can easily do so by using the 'using' syntax:

     private void PrintInventoryLevelsReportX()
            {
                using (ReportMngt.InventoryLevelReportMngt reportMngt = new DecEzy.ReportMngt.InventoryLevelReportMngt())
                {
                reportMngt.Print(BrandFilterID);
                }
            }

    This works if ReportMngt.InventoryLevelReportMngt implements IDisposable (it should).

    The 'using' is equivalent to using a try catch, with the object being disposed in the finally clause.

    If InventoryLevelReportMngt is a self brewed class, implement IDisposable, and in there, dispose of all the IDisposable objects it uses.


    Regards, Nico

    • Proposed as answer by Konrad Neitzel Friday, March 30, 2012 12:34 PM
    • Marked as answer by fweeee Wednesday, April 4, 2012 4:42 AM
    Friday, March 30, 2012 12:16 PM
  • hi,

    you should dispose of objects that implement the IDisposable interface.

    You can easily do so by using the 'using' syntax:

     private void PrintInventoryLevelsReportX()
            {
                using (ReportMngt.InventoryLevelReportMngt reportMngt = new DecEzy.ReportMngt.InventoryLevelReportMngt())
                {
                reportMngt.Print(BrandFilterID);
                }
            }

    This works if ReportMngt.InventoryLevelReportMngt implements IDisposable (it should).

    The 'using' is equivalent to using a try catch, with the object being disposed in the finally clause.

    If InventoryLevelReportMngt is a self brewed class, implement IDisposable, and in there, dispose of all the IDisposable objects it uses.


    Regards, Nico

    Thanks Nico,

    My classes are not currently implementing IDisposable interface, so I'm now trying to get that going.

    One thing that will complicate this is that I use some inheritance in my report management classes. I have a "BaseReportMngt.cs" class, then a class that inherits this, for each of the types of reports I use (3 of them), and then for each individual report I create a class that inherits the base report class for this type.

    So far I have implemented IDisposable in the BaseRreportMngt.cs class, as shown here; http://msdn.microsoft.com/en-us/library/system.idisposable.aspx . In the "protected virtual void Dispose(bool disposing)" class I have disposed of all the objects within this class that have a "Dispose" method.

    I suspect now I will need to override the Dispose(bool disposing) method in all of the inherited classes, and again add any objects that have the Dispose method, that are declared in this object.

    I'm having a problem, in that if I dispose of the report object (an XtraReport, by DevExpress), the report will not display. I suspect this is because I am not displaying the report modally, so the class continues to run after the report is run/displayed, disposing of the objects (including the report, currently displayed) while the report is being displayed (preview). If I print instead of previewing, I do not get this problem (the report actually prints).

    How do I get around this? How do I ensure that the report that is not being displayed modally gets removed from memory, seeing as though I cant do it in the dispose method? Do I have to attach the dispose method to the close event of the report or something?

    Friday, March 30, 2012 11:04 PM
  • Hi Fweee,

    If you take Nico's way, you don't need to call the dispose method manually.

    Have a nice day.


    Ghost,
    Call me ghost for short, Thanks
    To get the better anwser, it should be a better question.

    Sunday, April 1, 2012 5:43 AM
  • In addition, when an object is disposed, the memory may don't release immediately, but it doesnot do bad thing for your applications. When the memory will be collected, it depends on the GC.

    Ghost,
    Call me ghost for short, Thanks
    To get the better anwser, it should be a better question.

    Sunday, April 1, 2012 5:47 AM
  • Hi Fweee,

    If you take Nico's way, you don't need to call the dispose method manually.

    Have a nice day.


    Ghost,
    Call me ghost for short, Thanks
    To get the better anwser, it should be a better question.

    Ghost,

    This is assuming that my class has been set up to dispose correctly. My questions are about how to make the things within my class dispose correctly, because at the moment they are not (I can tell with a memory profileing tool, DotTrace).

    Sunday, April 1, 2012 9:58 AM
  • Fweee,

    i am not familiar with XtraReport but the fact that it displays a reports makes me think it is a control or at least a component.

    This does not change anything to the fact that you should implement IDisposable; it only changes how you should use this class.

    If the report is shown, it is obvious that Dispose should'nt be called until the user closes the containing form.

    Showing it modally makes this easier because the code halts until the form becomes invisible, but if, as you do, show it not-modally, it becomes difficult to track when the user closes the window. 

    The only way i can see is to try and hook up some kind of closing event to the report, if it exists, and handle that event in your report-containing class by disposing of the report.



    Regards, Nico

    Monday, April 2, 2012 7:08 AM
  • Fweee,

    i am not familiar with XtraReport but the fact that it displays a reports makes me think it is a control or at least a component.

    This does not change anything to the fact that you should implement IDisposable; it only changes how you should use this class.

    If the report is shown, it is obvious that Dispose should'nt be called until the user closes the containing form.

    Showing it modally makes this easier because the code halts until the form becomes invisible, but if, as you do, show it not-modally, it becomes difficult to track when the user closes the window. 

    The only way i can see is to try and hook up some kind of closing event to the report, if it exists, and handle that event in your report-containing class by disposing of the report.



    Regards, Nico

    Thanks Nico,

    I'm still looking into IDisposable. I have implemented it in the classes, but not quite good enough yet, as it is still not releasing the class or components, even when run using "Using".

    Yeah, there is a "OnClosing" and "OnClosed" event for the preview form. But I have hooked into the Disposed event for the preview form, and it is firing when I close the preview form, so I dont think that is the problem.

    The three classes (one inheriting from the other) are rather complex - they have lots of functionality for generating pdfs, previewing, printing, emailing, etc. So it could be on of these bits that I'm not handling right. I think I might have to take a copy of the classes, and remove components one at a time until they start disposing.

    Sounds like a good idea? I'm out of other ideas.

    Shanon.

    Monday, April 2, 2012 10:00 AM
  • Shanon,

    even with IDisposable correctly implemented and working, it is not abnormal that the memory is not released; the behaviour of dotnet applications is that it keeps on to the memory, even the disposed memory, until it is reclaimed by the os. Your profiling tool should have a function somewhere to 'reclaim' that memory, i suppose. 

    Also, if you hook events to your objects, be sure to set them to nothing/null after disposal.


    Regards, Nico

    Monday, April 2, 2012 11:23 AM
  • Thanks Nico,

    I have a vauge idea of how .NET manages memory, and I realise that while running a .NET application, you are not going to see the memory usage drop suddenly in the task manager if you close windows within the app. It is a bit more complicated then that.

    The basis of my conclusions is from using dotTrace. After running the same report 5 times in a row, then closing the form that was running the report, 5 instances of the report (along with the class that was calling it) remain in memory, while the form that was calling it is not in memory. If I call the reports a different way (far simpler way), they do not persist in memory.

    I'll have ae look at the events thing. That is one thing I havnt looked into to much yet.

    Shanon.

    Monday, April 2, 2012 11:30 AM
  • A quick update. I have made some progress with this. Unloading events helped, as well as removing command handlers (or something like that - forget what they were exactly).

    Now the problem is that my custom class calls another custom class, which calls another custom class, etc, none of which implement IDisposable. I'm now going through each one, making sure any class which is stopping another class from being disposed properly implements IDiposable.

    Wednesday, April 4, 2012 4:51 AM