none
Memory leak in floating arrays RRS feed

  • Question

  • Hi 

    We are using floating arrays. These arrays are huge in size of the order of more that 20000. Memory is not released when these arrays are set to null. What is the way to achieve release of memory.
    We found that even the destructor of the class containing the float array is not called.

    I have attached a code structure similar to our original one. Please let us know about any clues you might have to resolve the issue.



     

    public partial class Form1 : Form
    {
    public Form1()
    {
    InitializeComponent();
    }

    Blocks data;

    private void button1_Click(object sender, EventArgs e)
    {
    data = new Blocks();
    data.DataBlocks =
    new float[100000000];
    }

    private void button2_Click(object sender, EventArgs e)
    {
    GC.Collect();
    //Memory is not released verify in taskmgr.
    }

    }

    public class Blocks : IDisposable
    {
    private float[] blocks;
    public float[] DataBlocks
    {
    get{
    return blocks;
    }
    set
    {
    blocks =
    value;
    }
    }
    #region IDisposable Members
    private bool disposed = false;
    public void Dispose()
    {
    Dispose(
    true);
    GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
    // Check to see if Dispose has already been called
    if (!this.disposed)
    {
    if (disposing)
    {
    blocks =
    null;
    }
    // Note disposing has been done.
    disposed = true;
    }
    }

    ~Blocks()
    {
    //blocks = null;
    //GC.Collect();
    Dispose(false);
    }
    #endregion
    }

    Monday, January 5, 2009 10:34 AM

Answers

  • Implementing Dispose() on a class that contains only managed arrays is pointless.  The garbage collector is already able to track references, it doesn't need help.  The arrays are automatically collected when there are no references to the Blocks object left.  To make Button2 work, you'd have to set the data member to null before calling GC.Collect().  When the Form1 object gets collected, the Blocks object gets collected too without your help.  Beware that large arrays like the ones you are using are allocated in the Large Object Heap, it has different collection rules.

    Hans Passant.
    Tuesday, January 6, 2009 1:23 AM
    Moderator
  • "We found that even the destructor of the class containing the float array is not called."

    That's not a destructor, it's a finalizer.  Did you guys actually try to learn anything about C# and .NET before you started coding?  Your post sounds like you just assumed C# would work exactly like C++ because it looks similar.  Read "CLR via C#" by Jeffrey Richter before you try to write any more .NET code.
    Tuesday, January 6, 2009 8:56 AM

All replies

  • You're not setting calling Dispose() on your Disposable class.

    button2_Click should be calling data.Dispose() if it wants to free any memory. The GC.Collect() will work fine, but will not garbage collect "data" because there is still a reference to it.

          -Steve

    Monday, January 5, 2009 10:40 AM
  • Either call Dispose as Stephen suggested, or set the 'Blocks data;' variable to 'null'.
    Monday, January 5, 2009 10:59 PM
  • Implementing Dispose() on a class that contains only managed arrays is pointless.  The garbage collector is already able to track references, it doesn't need help.  The arrays are automatically collected when there are no references to the Blocks object left.  To make Button2 work, you'd have to set the data member to null before calling GC.Collect().  When the Form1 object gets collected, the Blocks object gets collected too without your help.  Beware that large arrays like the ones you are using are allocated in the Large Object Heap, it has different collection rules.

    Hans Passant.
    Tuesday, January 6, 2009 1:23 AM
    Moderator
  • "We found that even the destructor of the class containing the float array is not called."

    That's not a destructor, it's a finalizer.  Did you guys actually try to learn anything about C# and .NET before you started coding?  Your post sounds like you just assumed C# would work exactly like C++ because it looks similar.  Read "CLR via C#" by Jeffrey Richter before you try to write any more .NET code.
    Tuesday, January 6, 2009 8:56 AM
  • Hi All

    Thanks for your inputs.

    I am just upating the code a bit.

    If you see after execution of using statement control goes in Dispose method. where it sets the array to null.
    After that if you click on button 2 it calls GC. Even after that my memory doesnot reduces if you look in the task manager.


    namespace WindowsFormsApplication1

    {

    public partial class Form1 : Form

    {

    public Form1()

    {

    InitializeComponent();

    }

    private void button1_Click(object sender, EventArgs e)

    {

    using (Data dt = new Data())

    {

    }

    }

    private void button2_Click(object sender, EventArgs e)

    {

    GC.Collect();

    }

    }

    public class Data : IDisposable

    {

    float[] m_array;

    public Data()

    {

    m_array = new float[16384];

    }

    #region IDisposable Members

    // Track whether Dispose has been called.

    private bool disposed = false;

    // Do not make this method virtual.

    // A derived class should not be able to override this method.

    public void Dispose()

    {

    Dispose(true);

    // This object will be cleaned up by the Dispose method.

    // Therefore, you should call GC.SupressFinalize to

    // take this object off the finalization queue

    // and prevent finalization code for this object

    // from executing a second time.

    GC.SuppressFinalize(this);

    }

    // Dispose(bool disposing) executes in two distinct scenarios.

    // If disposing equals true, the method has been called directly

    // or indirectly by a user's code. Managed and unmanaged resources

    // can be disposed.

    // If disposing equals false, the method has been called by the

    // runtime from inside the finalizer and you should not reference

    // other objects. Only unmanaged resources can be disposed.

    private void Dispose(bool disposing)

    {

    // Check to see if Dispose has already been called.

    if (!this.disposed)

    {

    // If disposing equals true, dispose all managed

    // and unmanaged resources.

    if (disposing)

    {

    m_array = null;

    }

    // Call the appropriate methods to clean up

    // unmanaged resources here.

    // If disposing is false,

    // only the following code is executed.

    // Note disposing has been done.

    disposed = true;

    }

    }

    ~Data()

    {

    // Do not re-create Dispose clean-up code here.

    // Calling Dispose(false) is optimal in terms of

    // readability and maintainability.

    Dispose(false);

    }



    #endregion



    }

    }



     

    Thursday, January 15, 2009 10:55 AM
  • Don't use Taskmgr to diagnose memory usage, it is far too crude for that.  It shows working set size, the amount of virtual memory that is mapped into RAM.  Minimize your app's main window to make you feel better.
    Hans Passant.
    Thursday, January 15, 2009 1:06 PM
    Moderator
  • Thanks Hans.
    If memory consumption is high performance of the application degrades.

    This is what we are doing we load 100MB data. we remove 50MB out of that. We again load 50 MB. The memory gets reduced at some point of time after removal. but the performance becomes sluggish. The numbers are just for example our data may be huge than this.

    Can you please comment on this.
    Wednesday, January 21, 2009 12:07 PM