www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to delete dynamic array ?

reply "Ilya Yaroshenko" <ilyayaroshenko gmail.com> writes:
case 1:
  delete ar;
case 2:
  ar.destroy();
case 3:
  GC.free(ar.ptr);
case 4:
  ar = null;// (assumed that ar is only one pointer to the same 
array)

What is the difference?

How to free memory to the system immediately?

___________________________
Thank You & Best Regards,
Ilya
Dec 29 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Ilya Yaroshenko:

 case 1:
  delete ar;
It's deprecated.
 case 4:
  ar = null;// (assumed that ar is only one pointer to the same 
 array)
It's the simpler way.
 How to free memory to the system immediately?
What is your use case? Bye, bearophile
Dec 30 2013
parent reply mw <mingwu gmail.com> writes:
On Monday, 30 December 2013 at 08:13:30 UTC, bearophile wrote:
 How to free memory to the system immediately?
What is your use case?
The use case is: we want deterministic memory management, (and the application data is too big to fit into memory at once, so have to be processed batch by batch). suppose: double[] data; // D type: dynamic array As of 2021 what's the correct way to allocate and deallocate (free memory to the system immediately) D's dynamic array? If we use core.stdc.stdlib.malloc and free, e.g. ``` data = core.stdc.stdlib.malloc(n * double.sizeof); // processing ... free(data.ptr); ``` -- will data.length be set correctly (since it's a D type) with malloc? -- or we still need to manually set data.length = n? (in this case, will it become GC managed, which we want to avoid in this app)? Thanks.
Mar 16 2021
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Mar 16, 2021 at 11:28:00PM +0000, mw via Digitalmars-d-learn wrote:
[...]
 suppose:
 
   double[] data;  // D type: dynamic array
 
 As of 2021 what's the correct way to allocate and deallocate (free
 memory to the system immediately) D's dynamic array?
[...] Note that T[] is just a slice, not the dynamic array itself. The dynamic array is allocated and managed by the GC when you append stuff to it, or when you create a new array with `new` or an array literal. None of the latter, however, precludes you from using T[] for memory that you manage yourself. For example, you could do this: double[] data; data = cast(double[]) malloc(n * double.sizeof)[0 .. n]; Now you have a slice to memory you allocated yourself, and you have to manage its lifetime manually. When you're done with it: free(data.ptr); data = []; // null out dangling pointer, just in case The GC does not get involved unless you actually allocate from it. As long as .ptr does not point to GC-managed memory, the GC will not care about it. (Be aware, though, that the ~ and ~= operators may allocate from the GC, so you will have to refrain from using them. nogc may help in this regard.) T -- Computers shouldn't beep through the keyhole.
Mar 16 2021
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 16 March 2021 at 23:49:00 UTC, H. S. Teoh wrote:
 [snip]

 Note that T[] is just a slice, not the dynamic array itself. 
 The dynamic array is allocated and managed by the GC when you 
 append stuff to it, or when you create a new array with `new` 
 or an array literal.

 None of the latter, however, precludes you from using T[] for 
 memory that you manage yourself. For example, you could do this:

 	double[] data;
 	data = cast(double[]) malloc(n * double.sizeof)[0 .. n];

 Now you have a slice to memory you allocated yourself, and you 
 have to manage its lifetime manually.  When you're done with it:

 	free(data.ptr);
 	data = []; // null out dangling pointer, just in case

 The GC does not get involved unless you actually allocate from 
 it. As long as .ptr does not point to GC-managed memory, the GC 
 will not care about it. (Be aware, though, that the ~ and ~= 
 operators may allocate from the GC, so you will have to refrain 
 from using them.  nogc may help in this regard.)


 T
This is one of those things that is not explained well enough.
Mar 17 2021
next sibling parent reply Guillaume Piolat <first.name spam.org> writes:
On Wednesday, 17 March 2021 at 10:54:10 UTC, jmh530 wrote:
 This is one of those things that is not explained well enough.
Yes. I made this article to clear up that point: https://p0nce.github.io/d-idioms/#Slices-.capacity,-the-mysterious-property "That a slice own or not its memory is purely derived from the pointed area." could perhaps better be said "A slice is managed by the GC when the memory it points to is in GC memory"?
Mar 17 2021
next sibling parent frame <frame86 live.com> writes:
On Wednesday, 17 March 2021 at 14:30:26 UTC, Guillaume Piolat 
wrote:
 On Wednesday, 17 March 2021 at 10:54:10 UTC, jmh530 wrote:
 This is one of those things that is not explained well enough.
I want just to add, case 3 is wrong usage. Right one is: GC.free(GC.addrOf(ar.ptr));
Mar 17 2021
prev sibling next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 17 March 2021 at 14:30:26 UTC, Guillaume Piolat 
wrote:
 On Wednesday, 17 March 2021 at 10:54:10 UTC, jmh530 wrote:
 This is one of those things that is not explained well enough.
Yes. I made this article to clear up that point: https://p0nce.github.io/d-idioms/#Slices-.capacity,-the-mysterious-property "That a slice own or not its memory is purely derived from the pointed area." could perhaps better be said "A slice is managed by the GC when the memory it points to is in GC memory"?
I probably skimmed over the link when I originally read it without really understanding it. I'm able to understand it now. I think the underlying issue that needs to get explained better is that when you do int[] x = [1, 2, 3]; the result is always a GC-allocated dynamic array. However, z below int[3] y = [1, 2, 3]; int[] z = y[]; does not touch the GC at all. For a long time, I operated under the assumption that dynamic arrays and slices are the same thing and that dynamic arrays are always GC-allocated. z is obviously a slice of y, but it is also a dynamic array in the sense that you can append to it and get an array with one more member than y (except in nogc code). However, when appending to z, it seems that what's really happening is that the GC is allocating a new part of memory, copying over the original value of y and then copying in the new value. So it really becomes a new kind of thing (even if the type is unchanged). One takeaway is there is no issue with a function like below nogc void foo(T)(T[] x) {} so long as you don't actually need the GC within the function. A static array can be passed in just using a slice.
Mar 17 2021
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/17/21 12:06 PM, jmh530 wrote:
 On Wednesday, 17 March 2021 at 14:30:26 UTC, Guillaume Piolat wrote:
 On Wednesday, 17 March 2021 at 10:54:10 UTC, jmh530 wrote:
 This is one of those things that is not explained well enough.
Yes. I made this article to clear up that point: https://p0nce.github.io/d-idioms/#Slices-.capacity,-the-mysterious-property "That a slice own or not its memory is purely derived from the pointed area." could perhaps better be said "A slice is managed by the GC when the memory it points to is in GC memory"?
I probably skimmed over the link when I originally read it without really understanding it. I'm able to understand it now. I think the underlying issue that needs to get explained better is that when you do int[] x = [1, 2, 3]; the result is always a GC-allocated dynamic array. However, z below int[3] y = [1, 2, 3]; int[] z = y[]; does not touch the GC at all. For a long time, I operated under the assumption that dynamic arrays and slices are the same thing and that dynamic arrays are always GC-allocated. z is obviously a slice of y, but it is also a dynamic array in the sense that you can append to it and get an array with one more member than y (except in nogc code). However, when appending to z, it seems that what's really happening is that the GC is allocating a new part of memory, copying over the original value of y and then copying in the new value. So it really becomes a new kind of thing (even if the type is unchanged). One takeaway is there is no issue with a function like below nogc void foo(T)(T[] x) {} so long as you don't actually need the GC within the function. A static array can be passed in just using a slice.
This is why I view slices as not dynamic arrays. I think of a slice as pointing at memory. When you append it effectively: 1. Checks to see if the underlying memory is GC allocated. 2. If not, it allocates new GC memory to hold the original memory + the appended data 3. It appends the data to the GC block that it now must point at. In this way, it presents a dynamic array *interface*, but it's not necessarily pointing at a dynamic array type (at least in the way I think of a dynamic array type). I've had online battles about this terminology, and people asked me to change my array article to disavow this distinction, but I'm not going to change it. It's so much easier to understand. -Steve
Mar 17 2021
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 17 March 2021 at 16:20:06 UTC, Steven Schveighoffer 
wrote:
 [snip]
 
 I've had online battles about this terminology, and people 
 asked me to change my array article to disavow this 
 distinction, but I'm not going to change it. It's so much 
 easier to understand.

 -Steve
I'll be on your side on that one.
Mar 17 2021
prev sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 17 March 2021 at 16:20:06 UTC, Steven Schveighoffer 
wrote:

It's important to understand that [] is just a practical syntax 
for a fat pointer.

Thinking of [] just as a fancy pointer helps imho to clarify that 
the pointed to memory nature is independant of the pointer itself.
Mar 18 2021
parent Kagamin <spam here.lot> writes:
On Thursday, 18 March 2021 at 17:57:30 UTC, Patrick Schluter 
wrote:
 It's important to understand that [] is just a practical syntax 
 for a fat pointer.

 Thinking of [] just as a fancy pointer helps imho to clarify 
 that the pointed to memory nature is independant of the pointer 
 itself.
I think they are arrays alright. What's missing is expression of ownership, because D follows traditional language design approach, and traditionally ownership wasn't expressed in language and was done by convention.
Mar 19 2021
prev sibling parent reply Vinod K Chandran <kcvinu82 gmail.com> writes:
On Wednesday, 17 March 2021 at 14:30:26 UTC, Guillaume Piolat 
wrote:

 I made this article to clear up that point: 
 https://p0nce.github.io/d-idioms/#Slices-.capacity,-the-mysterious-property
Sorry for this off-topic question. I am amazed with eye catchy look of that d-idioms page. I want to create a page like it for my ongoing project. I think it's a good form of documentation. How do i create one like it ?
Mar 18 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 18 March 2021 at 18:48:26 UTC, Vinod K Chandran 
wrote:
 On Wednesday, 17 March 2021 at 14:30:26 UTC, Guillaume Piolat 
 wrote:

 I made this article to clear up that point: 
 https://p0nce.github.io/d-idioms/#Slices-.capacity,-the-mysterious-property
Sorry for this off-topic question. I am amazed with eye catchy look of that d-idioms page. I want to create a page like it for my ongoing project. I think it's a good form of documentation. How do i create one like it ?
The source code is here: https://github.com/p0nce/d-idioms/
Mar 18 2021
parent Vinod K Chandran <kcvinu82 gmail.com> writes:
On Thursday, 18 March 2021 at 21:21:37 UTC, Paul Backus wrote:

 The source code is here: https://github.com/p0nce/d-idioms/
Thanks for the answer. But it's more complex than I thought. Something like Latex was in my mind.
Mar 18 2021
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 3/17/21 3:54 AM, jmh530 wrote:
 On Tuesday, 16 March 2021 at 23:49:00 UTC, H. S. Teoh wrote:
 =C2=A0=C2=A0=C2=A0=C2=A0double[] data;
 =C2=A0=C2=A0=C2=A0=C2=A0data =3D cast(double[]) malloc(n * double.size=
of)[0 .. n];
 This is one of those things that is not explained well enough.
I have something here: =20 http://ddili.org/ders/d.en/pointers.html#ix_pointers.slice%20from%20point= er Ali
Mar 17 2021
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 17 March 2021 at 16:32:28 UTC, Ali Çehreli wrote:
 On 3/17/21 3:54 AM, jmh530 wrote:
 On Tuesday, 16 March 2021 at 23:49:00 UTC, H. S. Teoh wrote:
     double[] data;
     data = cast(double[]) malloc(n * double.sizeof)[0 .. n];
 This is one of those things that is not explained well enough.
I have something here: http://ddili.org/ders/d.en/pointers.html#ix_pointers.slice%20from%20pointer Ali
That's a little advanced, I think. And you also have http://ddili.org/ders/d.en/slices.html saying that slices are just another name for dynamic arrays.
Mar 17 2021
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 3/17/21 10:21 AM, jmh530 wrote:

 That's a little advanced, I think. And you also have
 http://ddili.org/ders/d.en/slices.html
 saying that slices are just another name for dynamic arrays.
I don't fully agree with myself there. :) Slices are interfaces to many different kinds of consecutive objects: nameless dynamic arrays owned by the GC, static arrays, dynamic arrays managed by the programmer, etc. The conflation stems from the fact that the storage for the slice becomes "a dynamic array owned by the GC" as soon as new storage is needed: appending, concatenation, and increasing the length. The slice leaves its existing storage just like that. Ali
Mar 17 2021
prev sibling parent mw <mingwu gmail.com> writes:
On Tuesday, 16 March 2021 at 23:49:00 UTC, H. S. Teoh wrote:
 On Tue, Mar 16, 2021 at 11:28:00PM +0000, mw via 
 Digitalmars-d-learn wrote: [...]
 suppose:
 
   double[] data;  // D type: dynamic array
 
 As of 2021 what's the correct way to allocate and deallocate 
 (free memory to the system immediately) D's dynamic array?
[...] Note that T[] is just a slice, not the dynamic array itself. The dynamic array is allocated and managed by the GC when you append stuff to it, or when you create a new array with `new` or an array literal. None of the latter, however, precludes you from using T[] for memory that you manage yourself. For example, you could do this: double[] data; data = cast(double[]) malloc(n * double.sizeof)[0 .. n];
correction: this should be: n *= double.sizeof; data = cast(double[])(malloc(n)[0 .. n]); // i.e. slice n == malloc n
 Now you have a slice to memory you allocated yourself, and you 
 have to manage its lifetime manually.  When you're done with it:

 	free(data.ptr);
 	data = []; // null out dangling pointer, just in case

 The GC does not get involved unless you actually allocate from 
 it. As long as .ptr does not point to GC-managed memory, the GC 
 will not care about it. (Be aware, though, that the ~ and ~= 
 operators may allocate from the GC, so you will have to refrain 
 from using them.  nogc may help in this regard.)


 T
Mar 25 2021
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
Answer will make more sense if ar is assumed to be any 
heap-allocated object, not just dynamic array.

On Monday, 30 December 2013 at 06:52:20 UTC, Ilya Yaroshenko 
wrote:
 case 1:
  delete ar;
Deprecated. Used to call destructor and GC.free after that
 case 2:
  ar.destroy();
Current solution to free resources in deterministic way. Calls destructor and sets `ar` to init state so that it can be collected by GC at some unknown point later.
 case 3:
  GC.free(ar.ptr);
Marks memory as freed in GC. Unsafe and discouraged because there can still be references pointing at it.
 case 4:
  ar = null;// (assumed that ar is only one pointer to the same 
 array)
Simply cleans the reference to an object. If it was the only reference, it will be destroyed and freed upon next GC cycle.
 What is the difference?

 How to free memory to the system immediately?
GC.free However, if you want deterministic deallocation it makes more sense to use C malloc or custom allocators as GC tends to run faster if it is aware of less memory.
Dec 30 2013
prev sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 30 December 2013 at 06:52:20 UTC, Ilya Yaroshenko 
wrote:
 case 1:
  delete ar;
 case 2:
  ar.destroy();
 case 3:
  GC.free(ar.ptr);
 case 4:
  ar = null;// (assumed that ar is only one pointer to the same 
 array)

 What is the difference?

 How to free memory to the system immediately?
It depends on how it is allocated. The `delete` operator is deprecated, so it is never appropriate. For GC memory (memory allocated with `new`, the concatenation operators or array literals) then you should just `null` any reference that is no longer used, leaving it to the GC to collect the memory when it sees fit. This guarantees memory safety, which is the primary purpose of a memory garbage collector. If you really, really must free a chunk of GC memory *right now*, you can use GC.free, but you lose any guarantee of memory safety. If you can't think of a reason your code needs to do this, then your code probably doesn't need it. If the array is allocated from a non-GC heap, such as the C heap, use the corresponding freeing function (C heap using `malloc` + `free`). `destroy` is for running destructors on, and then invalidating, instances of user-defined types (UDTs). For generic code purposes, you can use it on non-UDTs, in which case it will just invalidate them. Values invalidated with `destroy` must not be used after invalidation - it is a logic error. What it means by invalidation is up to the implementation, but it guarantees that it won't free memory. Currently, it zero-blasts the value (which may be different from the value's default initializer).
Dec 30 2013