April 25, 2022
On Mon, Apr 25, 2022 at 01:28:01PM +0000, Alain De Vos via Digitalmars-d-learn wrote:
> Could thc or hboehm provide solutions ?

In general, GC (of any kind) does not (and cannot) guarantee the order
objects will be collected in. So in the dtor, you cannot assume that any
objects you depend on still exist (they may have already been
collected).

There is also no guarantee that the object will *ever* get collected: in theory, the GC may only collect just enough to make space for further allocations, it's not obligated to collect *everything* that's collectible. Or the collection might not take place before the end of the program -- the GC may skip the final collection because it knows the OS will reclaim everything automatically anyway.

Basically, deterministic destruction and GC are antithetical to each other, and trying to have both is the road to trouble. If you wish to have deterministic destruction, don't use the GC; use RAII or reference counting instead.


T

-- 
What do you mean the Internet isn't filled with subliminal messages? What about all those buttons marked "submit"??
April 25, 2022

On Monday, 25 April 2022 at 02:07:50 UTC, Ali Çehreli wrote:

> >
 import core.memory: GC;
 GC.free(GC.addrOf(cast(void *)(i.ptr)));

That is wrong because you did not allocate that address yourself.

Hmm? The GC did allocate here(?)

>

On 4/24/22 17:26, Salih Dincer wrote:

>

MEM.free(i.ptr);
// You don't need to addrOf(cast(void*)i)

Wrong.

>

Good point about i.ptr but that free() does not or should not do anything because it is "memory not originally allocated by this garbage collector":

https://dlang.org/phobos/core_memory.html#.GC.free

Well... maybe it was allocated by that garbage collector and may be it points to the beginning of an allocated block but we don't know that. I wouldn't call free() on an array's memory.

Ali

And if it was, the freeing must be done with GC.addrOf or it will fail with larger arrays.

You will need the GC address to free the block. That is what __delete actually does - which was patched back recently, reported by Adam: https://issues.dlang.org/show_bug.cgi?id=21550

April 25, 2022
On 4/25/22 16:02, frame wrote:
> On Monday, 25 April 2022 at 02:07:50 UTC, Ali Çehreli wrote:
>> >      import core.memory: GC;
>>      GC.free(GC.addrOf(cast(void *)(i.ptr)));
>> That is wrong because you did not allocate that address yourself.
>
> Hmm? The GC did allocate here(?)

Yes. I still don't understand the need to free GC memory explicitly. I can understand GC.collect() but not the memory of a specific array.

>> On 4/24/22 17:26, Salih Dincer wrote:
>>
>> >    MEM.free(i.ptr);
>> >    // You don't need to addrOf(cast(void*)i)
>
> Wrong.

You are right. I missed the fact that addrOf is a GC function.

Ali

April 26, 2022
On Monday, 25 April 2022 at 14:25:17 UTC, H. S. Teoh wrote:
> On Mon, Apr 25, 2022 at 01:28:01PM +0000, Alain De Vos via Digitalmars-d-learn wrote:
>> Could thc or hboehm provide solutions ?
>
> In general, GC (of any kind) does not (and cannot) guarantee the order
> objects will be collected in. So in the dtor, you cannot assume that any
> objects you depend on still exist (they may have already been
> collected).
>
> There is also no guarantee that the object will *ever* get collected: in theory, the GC may only collect just enough to make space for further allocations, it's not obligated to collect *everything* that's collectible. Or the collection might not take place before the end of the program -- the GC may skip the final collection because it knows the OS will reclaim everything automatically anyway.
>
> Basically, deterministic destruction and GC are antithetical to each other, and trying to have both is the road to trouble. If you wish to have deterministic destruction, don't use the GC; use RAII or reference counting instead.
>
>
> T

When you can foresee a "maximum size" , you can create "deterministic" stack objects.

```
class C {
	@nogc this(){}
	@nogc this(int dummy){};
	@nogc int[3] fixarr=new int[3];
}//C

@nogc void myfun(){
	int a;
	scope c = new C();
	scope c2 = new C(5);
}//myfun

void main(){
	myfun();
}//main

```

It's just the variable length arrays which are "problematic". Feel free to elaborate.
April 30, 2022

On Sunday, 24 April 2022 at 21:00:50 UTC, Alain De Vod wrote:

>

Is this a correct program to explicit call destroy & free ?

void main(){
    int[] i=new int[10000];
    import object: destroy;
    destroy(i);
    import core.memory: GC;
    GC.free(GC.addrOf(cast(void *)(i.ptr)));
}

A few picks.

1: You do not need to import destroy. Everything in object is automatically imported.

2: As others have said, destroying an int, or an array if them, is meaningless, since they do not have destructors. The only thing your call does is to set i to null. In this case it means that there are no more references to the array, so the garbage collector can collect it at some point.

3: Because i is now null, GC.free also does nothing. If you had something that really mandated using destroy, you'd want to use destroy!false(i) to avoid setting i to null.

4: Manually freeing garbage collected memory is just as dangerous as freeing manually managed memory. It's preferable to just let the GC collect the memory. Also like said, there's probably no point to allocate with GC in the first place if you're going to manually free the memory.

5: If you're in a hurry to free the memory, a safer way is to call GC.collect. It will most likely free your old data immediately. Don't trust it quite 100% though, since it's possible that some unlucky bit pattern in your remaining data, that isn't really a pointer, "points" to your old data and it won't get collected. Using a precise GC would eliminate that risk I think.

This is rarely a problem though, as long as you either don't do anything mandatory in destructors, or use destroy before forgetting the data. The GC can still usually free the majority of your memory.

April 30, 2022

On Saturday, 30 April 2022 at 09:25:18 UTC, Dukc wrote:

>

On Sunday, 24 April 2022 at 21:00:50 UTC, Alain De Vod wrote:

>

[...]

A few picks.

1: You do not need to import destroy. Everything in object is automatically imported.

[...]

Hell, just using scope int[] i should be enough to trigger deterministic destruction, no? typecons's Scoped! template can be used if 100% guarantee is needed and the memory has to be stack allocated

April 30, 2022

On Saturday, 30 April 2022 at 11:37:32 UTC, Tejas wrote:

>

Hell, just using scope int[] i should be enough to trigger deterministic destruction, no? typecons's Scoped! template can be used if 100% guarantee is needed and the memory has to be stack allocated

Didn't think of that. To be frank, I don't know if scope int[] i means deterministic destruction. Scoped does IIRC.

May 03, 2022

Error: array literal in @nogc function test.myfun may cause a GC allocation

@nogc void myfun(){
scope int[] i=[1,2,3];
}//myfun

May is a fuzzy word...

May 03, 2022

On Tuesday, 3 May 2022 at 12:59:31 UTC, Alain De Vos wrote:

>

Error: array literal in @nogc function test.myfun may cause a GC allocation

@nogc void myfun(){
scope int[] i=[1,2,3];
}//myfun

May is a fuzzy word...

It means if the compiler is free to allocate on the stack if possible. In practice, though, you can usually assume there will be a GC allocation.

May 03, 2022

Note, It's not i'm against GC. But my preference is to use builtin types and libraries if possible,
But at the same time be able to be sure memory is given free when a variable is going out of scope.
It seems not easy to combine the two with a GC which does his best effort but as he likes or not.