Thread overview
Explicitly Freeing Memory
Nov 19, 2014
H. S. Teoh
Nov 19, 2014
Vladimir Panteleev
Nov 19, 2014
Kagamin
November 19, 2014
I posted a thread the other day explaining that I was running into a memory leak issue which is very hard to debug. There seems to be a false pointer somewhere, and I have no way of knowing where that is or which object is being pointed to. I decided to take the easy way out and explicitly free memory when I don't need it. Unfortunately, this brings about more problems.

I'm trying to explicitly free chunks of memory allocated with GC.malloc() in a destructor. This works fine while the program is running, but when the program terminates, it seems the GC calls all destructors in an arbitrary order. I then get a core.exception.InvalidMemoryOperationError because I'm trying to free memory that is already freed.

Not quite sure where to go from here... I guess I'd have to allocate all of the objects I want to free outside of GC'd space, but D doesn't seem to provide a convenient syntax for doing so. The alternate solution I'm considering is to have a special function to destroy all the objects owned by my parent object before destroying the parent object itself, and calling this function explicitly.
November 19, 2014
On Wed, Nov 19, 2014 at 03:47:03AM +0000, Maxime Chevalier-Boisvert via Digitalmars-d-learn wrote: [...]
> I'm trying to explicitly free chunks of memory allocated with GC.malloc() in a destructor. This works fine while the program is running, but when the program terminates, it seems the GC calls all destructors in an arbitrary order. I then get a core.exception.InvalidMemoryOperationError because I'm trying to free memory that is already freed.
[...]

Yeah, it is well-known that relying on destructor calling order is a bad idea. The GC makes no guarantees about what order destructors will get called, if they get called at all. Also, calling GC allocation / deallocation functions from inside a dtor is also a bad idea, since the GC is not reentrant.

Unfortunately I don't have any good suggestions... I have been avoiding depending on dtors in D because of the aforementioned issues (and more), so I haven't had much experience in debugging dtor-related problems in D.


T

-- 
An elephant: A mouse built to government specifications. -- Robert Heinlein
November 19, 2014
On Wednesday, 19 November 2014 at 03:47:04 UTC, Maxime Chevalier-Boisvert wrote:
> I posted a thread the other day explaining that I was running into a memory leak issue which is very hard to debug. There seems to be a false pointer somewhere, and I have no way of knowing where that is or which object is being pointed to. I decided to take the easy way out and explicitly free memory when I don't need it. Unfortunately, this brings about more problems.
>
> I'm trying to explicitly free chunks of memory allocated with GC.malloc() in a destructor. This works fine while the program is running, but when the program terminates, it seems the GC calls all destructors in an arbitrary order. I then get a core.exception.InvalidMemoryOperationError because I'm trying to free memory that is already freed.

InvalidMemoryOperationError occurs when you're trying to invoke GC functions during a GC pass (because the current D GC is non-reentrant). This can occur if you explicitly free objects from the destructor, and the destructor is invoked by the GC.

I suppose you can work around this by using a separate function which deallocates owned objects' memory.

P.S. Still working on Diamond.
November 19, 2014
> Unfortunately I don't have any good suggestions... I have been avoiding
> depending on dtors in D because of the aforementioned issues (and more),
> so I haven't had much experience in debugging dtor-related problems in
> D.

I decided to just free everything explicitly:

https://github.com/maximecb/Higgs/blob/03931178deb5794bf27b1020542d102a08286c07/source/runtime/vm.d#L784

It seems to address my memory leak issue for the moment: `make test` uses about 1/3 the memory and runs more than twice as fast.
November 19, 2014
You can control it by creating a global flag and checking it before freeing.