www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Dynamic Array Question

reply Dax <dax mailinator.com> writes:
Hi!
I'm working on a library written in D.
After some tests I have discovered that my library leaks memory, those leaks
are caused by dynamics array that I use in my library.

My question is:
Should dynamics array be deallocated automatically when a procedure returns?
There is another way to acomplish this?

Maybe I'm doing something wrong, so, I post the function that causes the leak:

public string getWindowText(HWND hWnd)
{
  int len = GetWindowTextLengthW(hWnd);
  wchar[] t = new wchar[len + 1]; // How to deallocate this?

  GetWindowTextW(hWnd, t.ptr, len);

  /*
   * I'm converting the wchar[] to char[],
   * the variable 't' should be deallocated
   * because I not need it anymore.
   */
  return to!(string)(t[0..len]);
}

Thanks,
Dax
Sep 20 2011
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 20 Sep 2011 14:06:34 -0400, Dax <dax mailinator.com> wrote:

 Hi!
 I'm working on a library written in D.
 After some tests I have discovered that my library leaks memory, those  
 leaks are caused by dynamics array that I use in my library.

 My question is:
 Should dynamics array be deallocated automatically when a procedure  
 returns?

No, in a GC-enabled language, the GC is responsible for cleaning up the memory.
 There is another way to acomplish this?

Yes, you can manually free the memory at your own risk. Note that in any GC-enabled language, more memory is consumed than in a manually-managed language. This is because there is a time period where a memory block is unused, but still allocated (i.e. the GC hasn't collected it yet). D's garbage collector is conservative, which means it may keep some blocks in memory even though they are no longer in use. Also, depending on your measurement tools, you may be counting freed memory towards memory usage. For example, if a block of memory is deallocated, it's not given back to the OS, it simply goes back into a pool to be reallocated again later.
 Maybe I'm doing something wrong, so, I post the function that causes the  
 leak:

 public string getWindowText(HWND hWnd)
 {
   int len = GetWindowTextLengthW(hWnd);
   wchar[] t = new wchar[len + 1]; // How to deallocate this?

   GetWindowTextW(hWnd, t.ptr, len);

   /*
    * I'm converting the wchar[] to char[],
    * the variable 't' should be deallocated
    * because I not need it anymore.
    */
   return to!(string)(t[0..len]);
 }

You can deallocate the original array. The soon-to-be-deprecated method (but easiest) is: delete t; To avoid having to change your other code, I'd do this: wchar[] t = ...; scope(exit) delete t; // add this line to the end of the function (after returning) There is another way, but it's not as easy: // put this at the top of file import core.memory; ... scope(exit) GC.free(t.ptr); However, this is what will be required when delete is deprecated. -Steve
Sep 20 2011
parent travert phare.normalesup.org (Christophe) writes:
 To avoid having to change your other code, I'd do this:
 
 wchar[] t = ...;
 scope(exit) delete t; // add this line to the end of the function (after  
 returning)
 
 There is another way, but it's not as easy:
 
 // put this at the top of file
 import core.memory;
 
 ...
 
 scope(exit) GC.free(t.ptr);

does "scope wchar[] t = ...;" work too ?
Sep 20 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, September 20, 2011 11:06 Dax wrote:
 Hi!
 I'm working on a library written in D.
 After some tests I have discovered that my library leaks memory, those
 leaks are caused by dynamics array that I use in my library.
 
 My question is:
 Should dynamics array be deallocated automatically when a procedure
 returns? There is another way to acomplish this?
 
 Maybe I'm doing something wrong, so, I post the function that causes the
 leak:
 
 public string getWindowText(HWND hWnd)
 {
 int len = GetWindowTextLengthW(hWnd);
 wchar[] t = new wchar[len + 1]; // How to deallocate this?
 
 GetWindowTextW(hWnd, t.ptr, len);
 
 /*
 * I'm converting the wchar[] to char[],
 * the variable 't' should be deallocated
 * because I not need it anymore.
 */
 return to!(string)(t[0..len]);
 }

You don't deallocate dynamic arrays. The GC manages them. The GC manages all of the memory that you allocate in D with new. If the memory gets freed, it gets freed during a garbage collection cycle. When the GC runs is non- deterministic. I believe that it normally only ever gets called when new is called, and it's only going to run when new is called if it thinks that it needs to run. The fact that your program doesn't reference a chunk of memory anymore is irrelevant until a garbage collection cycle runs. That memory won't be freed until then. However last I heard, the GC still never released memory to the OS, and if that's still true, even if the GC collects the memory so that your program can reuse it, the memory usage of your program will never actually go down. So, if what you're doing is looking at the memory usage of your program, that may never go down regardless. - Jonathan M Davis
Sep 20 2011
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/20/2011 08:06 PM, Dax wrote:
 Hi!
 I'm working on a library written in D.
 After some tests I have discovered that my library leaks memory, those leaks
are caused by dynamics array that I use in my library.

Does it 'leak'? What is your exact setup, why isn't the GC collecting that memory?
 My question is:
 Should dynamics array be deallocated automatically when a procedure returns?
There is another way to acomplish this?

 Maybe I'm doing something wrong, so, I post the function that causes the leak:

 public string getWindowText(HWND hWnd)
 {
    int len = GetWindowTextLengthW(hWnd);
    wchar[] t = new wchar[len + 1]; // How to deallocate this?

    GetWindowTextW(hWnd, t.ptr, len);

    /*
     * I'm converting the wchar[] to char[],
     * the variable 't' should be deallocated
     * because I not need it anymore.
     */
    return to!(string)(t[0..len]);
 }

Unless the string gets extremely long, you could allocate it on the stack: wchar[] t=(cast(wchar*)alloca(wchar.sizeof*(len+1)))[0..len+1];
Sep 20 2011
parent Dax <dax mailinator.com> writes:
 Does it 'leak'? What is your exact setup, why isn't the GC collecting
 that memory?

I have a Label class with a text() property that calls the procedure that I have written in my first post and returns the result. I have posted here because I was looking the memory usage (more precisely the process' private working set) with Process Explorer (from Sysinternals) and I saw the private working set increase and increase every time text() property il called, so I trought it was a memory leak. But, if the Garbage Collector handles the memory allocation of dynamic arrays, the problem is solved. Thanks to all for help me with this problem! :)
Sep 20 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, September 20, 2011 21:48:10 Christophe wrote:
 To avoid having to change your other code, I'd do this:
 
 wchar[] t = ...;
 scope(exit) delete t; // add this line to the end of the function (after
 returning)
 
 There is another way, but it's not as easy:
 
 // put this at the top of file
 import core.memory;
 
 ...
 
 scope(exit) GC.free(t.ptr);

does "scope wchar[] t = ...;" work too ?

I'm not sure, but scope as a modifier on local variables like that is going to be removed from the language. std.typecons.Scoped is replacing it. However, unless you're having major memory issues, I really wouldn't worry about it. Just let the garbage collector do its thing. It's not the best, but it works fine in most cases. - Jonathan M Davis
Sep 20 2011
prev sibling next sibling parent Jesse Phillips <jessekphillips+d gmail.com> writes:
On Tue, 20 Sep 2011 14:28:54 -0400, Steven Schveighoffer wrote:

 You can deallocate the original array.  The soon-to-be-deprecated method
 (but easiest) is:
 
 delete t;
 
 To avoid having to change your other code, I'd do this:
 
 wchar[] t = ...;
 scope(exit) delete t; // add this line to the end of the function (after
 returning)

Unless I missed something, delete is being removed from the language.
Sep 20 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 21 Sep 2011 00:09:08 -0400, Jesse Phillips  
<jessekphillips+d gmail.com> wrote:

 On Tue, 20 Sep 2011 14:28:54 -0400, Steven Schveighoffer wrote:

 You can deallocate the original array.  The soon-to-be-deprecated method


Note: ^^^^^^^^^^^^^^^^^^^^^^^^^ :)
 (but easiest) is:

 delete t;

 To avoid having to change your other code, I'd do this:

 wchar[] t = ...;
 scope(exit) delete t; // add this line to the end of the function (after
 returning)

Unless I missed something, delete is being removed from the language.

-Steve
Sep 22 2011