www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - struct destructor

reply Alain De Vos <devosalain ymail.com> writes:
When I do a "new" in a struct constructor to assign to a member 
variable of this struct, what do i write in the same struct 
destructor to free the memory ?
May 15 2021
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 15 May 2021 at 16:52:10 UTC, Alain De Vos wrote:
 When I do a "new" in a struct constructor to assign to a member 
 variable of this struct, what do i write in the same struct 
 destructor to free the memory ?
If you used `new` the garbage collector is responsible for it.
May 15 2021
parent reply Alain De Vos <devosalain ymail.com> writes:
On Saturday, 15 May 2021 at 16:53:04 UTC, Adam D. Ruppe wrote:
 On Saturday, 15 May 2021 at 16:52:10 UTC, Alain De Vos wrote:
 When I do a "new" in a struct constructor to assign to a 
 member variable of this struct, what do i write in the same 
 struct destructor to free the memory ?
If you used `new` the garbage collector is responsible for it.
Can I send a kind message to the garbage collector to please free that speficic memory at that time specified ?
May 15 2021
parent reply Alain De Vos <devosalain ymail.com> writes:
Feature request, a function old which does the opposite of new, 
allowing deterministic,real-time behavior and memory conservation.
May 15 2021
next sibling parent reply Dennis <dkorpel gmail.com> writes:
On Saturday, 15 May 2021 at 17:55:17 UTC, Alain De Vos wrote:
 Feature request, a function old which does the opposite of new, 
 allowing deterministic,real-time behavior and memory 
 conservation.
You can use [object.destroy](https://dlang.org/phobos/object.html#.destroy) to destruct, and [GC.free](https://dlang.org/phobos/core_memory.html#.GC.free) to free memory allocated with `new`.
May 15 2021
next sibling parent reply Alain De Vos <devosalain ymail.com> writes:
Thanks, good idea but,
It does not initiate a GC cycle or free any GC memory.
May 15 2021
next sibling parent Alain De Vos <devosalain ymail.com> writes:
Sorry free does , indeed.
May 15 2021
prev sibling parent reply cc <cc nevernet.com> writes:
On Saturday, 15 May 2021 at 18:24:19 UTC, Alain De Vos wrote:
 Thanks, good idea but,
 It does not initiate a GC cycle or free any GC memory.
Personally I wish D would re-implement "delete" and make it "just work" like one would assume, but from what I've seen there have been many many debates on that and it isn't going to happen. If the goal is to absolutely squeeze the GC back down after using new or dynamic arrays, I find destroy + GC.free often fails to do the trick (e.g. GC.stats.usedSize remains high). For whatever reason (I glanced at the code but haven't found the magic yet), the deprecated __delete does a more thorough job of making sure that memory actually gets "given up" on a collection cycle (particularly if you invoke it manually with `GC.collect(); GC.minimize();`. Presumably this isn't a desirable coding behavior, though. In my field (games), I do do something like this after initially loading the data to free up all the unused clutter and scaffolding, but it's very slow to call it every frame if you've been using the GC to create and delete game entities. So like Adam says, standard C malloc/free are probably the best way to go in this case. ```d import core.stdc.stdlib; import core.lifetime; class Foo {} auto foo = cast(Foo) malloc(__traits(classInstanceSize, Foo)); emplace!Foo(foo, /*constructor args*/); // ... destroy(foo); free(cast(void*)foo); ``` Another alternative is something like the memutils library: https://code.dlang.org/packages/memutils ```d class Foo {} auto foo = ThreadMem.alloc!Foo(/*constructor args*/) ThreadMem.free(foo); // calls destroy for you, but can still destroy manually ``` You'll still need to be very careful about any GC mem that gets allocated within a class like this as it can get lost into the ether and cause permanent bloat. I've been doing a lot of iteration tests lately across a whole bunch of different memory management solutions and the state of discrete memory management in D for gaming applications is.. not great. I love D, but for all that it's designed to help reduce programmer error, it goes the opposite way once you start breaking free of the GC and having to be extra careful tiptoeing around its edges. Unfortunately I don't like doing the pure nogc/betterC route either, the GC is still really handy to have when you need it (and are aware that it's being used!), but GC collections during high intensity gaming are unacceptable (and deferring them to some later point doesn't help much either). Fair warning, I'm not one of the D elite with a deep guru-level knowledge of just precisely how everything is operating under the hood, so part of this may come down to learning better practices, but a problem I see IMO is a perceived lack of support or sympathy for coders who want to use the GC when it's nice, but not have it smack them in the face when it isn't. Even with the various articles and forum threads explaining D's memory options, there's still a general air of "You really should just be using the GC, so enjoy your no-man's land, you're on your own." Whether this is only an unfair perception and matter of documentation, or something that actually needs to be addressed in the language, is beyond simply me to decide, but I think a lot of outsiders coming into D may run into the same situation.
May 16 2021
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 16 May 2021 at 08:04:06 UTC, cc wrote:
 If the goal is to absolutely squeeze the GC back down after 
 using new or dynamic arrays, I find destroy + GC.free often 
 fails to do the trick (e.g. GC.stats.usedSize remains high).
destroy + GC.free has a quirk - GC.free only works on what GC.malloc returns, a base pointer, NOT what `new` returns. The documentation says this but it is a subtle detail easy to miss... ...including by other stdlib authors. __delete is simply incorrectly implemented and an accidental no-op in most cases! https://issues.dlang.org/show_bug.cgi?id=21550 The documentation that describes how to migrate away from `delete` made this same error. I tracked down the problem but wasn't 100% sure about the fix. Adding the GC.baseOf thing works for me but i didn't upstream since idk if it works for everyone else. maybe i should just do it though.
May 16 2021
next sibling parent mw <mingwu gmail.com> writes:
On Sunday, 16 May 2021 at 11:42:19 UTC, Adam D. Ruppe wrote:
 On Sunday, 16 May 2021 at 08:04:06 UTC, cc wrote:
 If the goal is to absolutely squeeze the GC back down after 
 using new or dynamic arrays, I find destroy + GC.free often 
 fails to do the trick (e.g. GC.stats.usedSize remains high).
destroy + GC.free has a quirk - GC.free only works on what GC.malloc returns, a base pointer, NOT what `new` returns. The documentation says this but it is a subtle detail easy to miss...
Right, we should always enforce malloc/free, new/delete are used in pairs, but not mixing them. Un-deprecate `delete`?
May 16 2021
prev sibling next sibling parent frame <frame86 live.com> writes:
On Sunday, 16 May 2021 at 11:42:19 UTC, Adam D. Ruppe wrote:
 On Sunday, 16 May 2021 at 08:04:06 UTC, cc wrote:
 I tracked down the problem but wasn't 100% sure about the fix. 
 Adding the GC.baseOf thing works for me but i didn't upstream 
 since idk if it works for everyone else.

 maybe i should just do it though.
I don't know it it is really affected but there is also a GC.free with just .ptr in AAs implementation in resize(). As I am understanding this issue it would lead to memory leaks on buckets (on re-used AA or if it cannot be set to null) with many items that are shrinking or growing over time. And any pointer in the buckets entry would be seen alive too? I know that are edge cases but still... maybe you could have a look at these things in the runtime source too.
May 20 2021
prev sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Sunday, 16 May 2021 at 11:42:19 UTC, Adam D. Ruppe wrote:
 On Sunday, 16 May 2021 at 08:04:06 UTC, cc wrote:
 [...]
destroy + GC.free has a quirk - GC.free only works on what GC.malloc returns, a base pointer, NOT what `new` returns. The documentation says this but it is a subtle detail easy to miss... ...including by other stdlib authors. __delete is simply incorrectly implemented and an accidental no-op in most cases! https://issues.dlang.org/show_bug.cgi?id=21550 The documentation that describes how to migrate away from `delete` made this same error. I tracked down the problem but wasn't 100% sure about the fix. Adding the GC.baseOf thing works for me but i didn't upstream since idk if it works for everyone else. maybe i should just do it though.
I'd say do it and then >9000 devs will comment, possibly leading to the truth. No comments = it's already acceptable.
May 20 2021
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 15 May 2021 at 18:15:24 UTC, Dennis wrote:
 On Saturday, 15 May 2021 at 17:55:17 UTC, Alain De Vos wrote:
 Feature request, a function old which does the opposite of 
 new, allowing deterministic,real-time behavior and memory 
 conservation.
You can use [object.destroy](https://dlang.org/phobos/object.html#.destroy) to destruct, and [GC.free](https://dlang.org/phobos/core_memory.html#.GC.free) to free memory allocated with `new`.
Specifically you wanna do: ``` .destroy(*ptr); GC.free(GC.addrOf(ptr)); ```
May 15 2021
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 15 May 2021 at 17:55:17 UTC, Alain De Vos wrote:
 Feature request, a function old which does the opposite of new, 
 allowing deterministic,real-time behavior and memory 
 conservation.
You're best off doing malloc+free if you want complete control though.
May 15 2021
next sibling parent Alain De Vos <devosalain ymail.com> writes:
I'll try first the first tip of Adam, here the code,

```
import std.stdio:writeln;
import core.memory: GC;
void myfun(){
class C{
	int[10000] x;
	}//class C
	
struct S {
	C c=null;
	 disable this();

	this(int dummy) {
		c=new C();
		writeln("Constructor");
		};//Constructor

	~this(){
		writeln("Destructor");
		.destroy(c);
		void * address=GC.addrOf(cast(void *)c);
		GC.free(address);
		};//destructor
}//struct S
S mys=S(0);
};//myfun()

void main(){
	myfun();
};//main
```
May 15 2021
prev sibling parent mw <mingwu gmail.com> writes:
On Saturday, 15 May 2021 at 18:26:08 UTC, Adam D. Ruppe wrote:
 On Saturday, 15 May 2021 at 17:55:17 UTC, Alain De Vos wrote:
 Feature request, a function old which does the opposite of 
 new, allowing deterministic,real-time behavior and memory 
 conservation.
You're best off doing malloc+free if you want complete control though.
You can use the heapAlloc / heapFree pair: https://wiki.dlang.org/Memory_Management#Explicit_Class_Instance_Allocation Which I added to my package here :-) https://code.dlang.org/packages/jdiutil https://github.com/mingwugmail/jdiutil/blob/master/source/jdiutil/memory.d
May 15 2021