www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Question: gc and dll functions

reply WB <wb sapo.pt> writes:
Hello,

Her I am with my first question. 

The Chapters about Garbage Collection  states:

Interfacing Garbage Collected Objects With Foreign Code
(...) then the collecter will miss it and free the memory.
To avoid this from happening,
* Maintain a root to the object in an area the collector does scan for
roots.

Would this allow for:

class Foo 
{
	char[] buffer;

	void bar() 
	{
		buffer.length = 1024;
		someDlFunction ( toStringz(buffer), buffer.length ); 
		/* someDlFunction writes to the buffer */
	}
}

void main() { new Foo.bar(); }


But, later on the same chapter says:
A copying garbage collector can arbitrarily move objects around in
memory (...)
(...)since, again, the garbage collector can move objects around in
memory

Doesn't this mean that GC may kick in while I am inside the Dll
function, move around the objects, and invalidade the pointer before
the Dll actually writes to it?

Another case: You register a buffer pointer in a Dll (maintaining a
root in GC memory), then half an hour later you call another function
of the same Dll that writes to that buffer. Did or did not the GC
invalidade the pointer meanwhile?

And is it the same if the buffer is declared at module level?

I ask because the manual says "Maintain a root to the object in an
area the collector does scan for roots.", which would allow to avoid
c.malloc and tracking memory by myself. Otherwise, how can this be
done if gc moves around the objects? What have I missed?

Thank you in advance.

wb
Sep 09 2004
parent reply pragma <pragma_member pathlink.com> writes:
Hi there.  I have some experience in this area, so I'll try to answer these as
best I can.

In article <rct0k0lksn57lpv2a2bf9uh3rbtg3hk03p 4ax.com>, WB says...
class Foo 
{
	char[] buffer;

	void bar() 
	{
		buffer.length = 1024;
		someDlFunction ( toStringz(buffer), buffer.length ); 
		/* someDlFunction writes to the buffer */
	}
}

void main() { new Foo.bar(); }
Your example is mostly correct, however your buffer is likely to be collected since its scope (the Foo object) is also subject to collection, as it won't last very long.
Another case: You register a buffer pointer in a Dll (maintaining a
root in GC memory), then half an hour later you call another function
of the same Dll that writes to that buffer. Did or did not the GC
invalidade the pointer meanwhile?
Odds are, you loose the object since the root inside the dll isn't honored by the exe's GC automatically.
And is it the same if the buffer is declared at module level?
D's modules have nothing to do with what is and is not a root, if that's what you're asking. :) Allow me to elaborate: Generally speaking, you should treat both sides of the dll divide as though they weren't coded in D all at all. This is because every exe and dll coded in D will have its own GC. In order for a given object to avoid collection, its GC of origin will need to be able to trace that object back to some non-collectable root reference or pointer in its own space. The exe's GC doesn't scan the dll's roots and vice versa. This is why the documentation reccomends copying all of your data across the exe/dll divide to avoid accidentally passing an object off to the wrong collector. Simply maintaining a root in a dll, to an instance from the exe won't work since the exe's GC won't be looking at the dll's roots. The rule of thumb is: if you 'new' an object in the exe, it needs a root in the exe. Likewise for a dll.
But, later on the same chapter says:
A copying garbage collector can arbitrarily move objects around in
memory (...)
(...)since, again, the garbage collector can move objects around in
memory

Doesn't this mean that GC may kick in while I am inside the Dll
function, move around the objects, and invalidade the pointer before
the Dll actually writes to it?

I ask because the manual says "Maintain a root to the object in an
area the collector does scan for roots.", which would allow to avoid
c.malloc and tracking memory by myself. Otherwise, how can this be
done if gc moves around the objects? What have I missed?
If it helps: feel free to ignore the comments in the docs about a copying GC, as this is not implemented yet. You may treat object references as though they never change outside what you explicitly do in your code. - Pragma [[ Eric Anderton at (dll) yahoo dot com ]]
Sep 09 2004
parent reply WOB <wb sapo.pt> writes:
Sorry, I changed my nick for this group since I realized that Walter
is actually Walter Bright... oops


On Thu, 9 Sep 2004 17:21:30 +0000 (UTC), pragma
<pragma_member pathlink.com> wrote:

And is it the same if the buffer is declared at module level?
D's modules have nothing to do with what is and is not a root, if that's what you're asking. :)
Yes I mixed it up at this point but of course I am talking about memory objects
If it helps: feel free to ignore the comments in the docs about a copying GC, as
this is not implemented yet.  You may treat object references as though they
never change outside what you explicitly do in your code.
Yes of course this helps. Due to your detailed answer, I think i got it now: It is perfectly safe to use gc allocated pointers for a short trip into another dll, having them released as soon an the function returns. But you don't store those pointer values in another Dll for later use. Just like you don't store them in a file either. But maybe it would be good practice to always use gc.disable() before calling a Dll function, just in case the copying GC gets implemented at some time in the future? Thanks a lot. wb
Sep 09 2004
parent pragma <pragma_member pathlink.com> writes:
In article <1ij1k0t5q129od2hcl0ljk265ra7im6sb9 4ax.com>, WOB says...
If it helps: feel free to ignore the comments in the docs about a copying GC, as
this is not implemented yet.  You may treat object references as though they
never change outside what you explicitly do in your code.
Yes of course this helps.
Glad I could be of assistance.
Due to your detailed answer, I think i got it now: It is perfectly
safe to use gc allocated pointers for a short trip into another dll,
having them released as soon an the function returns. But you don't
store those pointer values in another Dll for later use. Just like you
don't store them in a file either. 
Yep, that's the gist of it. Until D has some way to better "mesh" dlls together under the same GC, this will be the way forward.
But maybe it would be good practice
to always use gc.disable() before calling a Dll function, just in case
the copying GC gets implemented at some time in the future?
That would work, but you may want to investigate the performance aspects first (if any really apply). That and you'd want to make sure that you never miss the call to gc.enable(). I would think that when D gets a copying GC, one of two things will happen: - We'll get a gc.pin(void*) function that would prevent a chunk of memory from moving - Or all references will really point to a "descriptor" that will in turn reference the movable chunk of memory. The double-de-referencing would make the copying GC transparent to the program. But I'm not of any authority here, so who knows what will happen.
Thanks a lot.
Think nothing of it. ;) - Pragma [[ Eric Anderton at yahoo dot com ]]
Sep 10 2004