Thread overview
Dynamic Array Question
Sep 20, 2011
Dax
Sep 20, 2011
Christophe
Sep 21, 2011
Jonathan M Davis
Sep 21, 2011
Jesse Phillips
Sep 20, 2011
Jonathan M Davis
Sep 20, 2011
Timon Gehr
Sep 20, 2011
Dax
September 20, 2011
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
September 20, 2011
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
September 20, 2011
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
September 20, 2011
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];



September 20, 2011
>
> 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! :)
September 20, 2011
> 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 ?
September 21, 2011
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
September 21, 2011
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.
September 22, 2011
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