www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Garbage collection and closures.

reply ANtlord <antlord92 gmail.com> writes:
Hello! I can't understand one thing related to closures and 
calling of GC. I have the following demo snippet, where a closure 
is passed to `receive` function in a loop.

bool isDone = false;
while(!isDone)
	receive((bool val){ isDone = val });

Is GC called every iteration of this loop?

I know that I can move the code to a method of a struct and make 
the closure and variable "isDone" as fields of the struct. It 
avoids GC calling definitely. But I want to get how many times GC 
is called in case of a closure in a loop.

Thanks.
Jun 17
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 17 June 2017 at 13:03:28 UTC, ANtlord wrote:
 Is GC called every iteration of this loop?
No, it will once on scope entry; where the deepest-referenced variable that is actually captured is defined. The compiler allocates heap space instead of stack space for the locals, then runs the function normally using that space. The current implementation doesn't quite do this - it actually will alloc only once, on function entry, even when there's a variable inside a loop that is supposed to be independent. This is the cause of the commonly-referenced bug with foreach(i; whatever) capture(i); all showing the same number. When that bug is fixed, it is possible to allocate on each loop... but your code doesn't anyway, so you're ok. It will only alloc once. You can prove this with a debugger btw, set a breakpoint on `_d_allocmemory`.
Jun 17
parent reply ANtlord <antlord92 gmail.com> writes:
On Saturday, 17 June 2017 at 13:13:17 UTC, Adam D. Ruppe wrote:
 On Saturday, 17 June 2017 at 13:03:28 UTC, ANtlord wrote:
 Is GC called every iteration of this loop?
No, it will once on scope entry; where the deepest-referenced variable that is actually captured is defined. The compiler allocates heap space instead of stack space for the locals, then runs the function normally using that space.
Excuse me, I can't get what does it mean "deepest-referenced". What the deep you mean? The deep of a closure or deep of the function where the variable is defined. Can you give an example code?
 It will only alloc once. You can prove this with a debugger 
 btw, set a breakpoint on `_d_allocmemory`.
Is this function called every time when allocation happens in a heap? Thank you. Sorry if my English is not clear.
Jun 17
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 17 June 2017 at 14:19:34 UTC, ANtlord wrote:
 Excuse me, I can't get what does it mean "deepest-referenced". 
 What the deep you mean? The deep of a closure or deep of the 
 function where the variable is defined. Can you give an example 
 code?
Where the variable is defined that is referenced in the closure. So: --- void uses(void delegate() dg); void foo() { int a; foreach(b; 0 .. 10) { uses( () { a++; } ); // #1 uses( () { b++; } ); // #2 } } --- In that case, #1 would only be allocated once, at the start of the foo() function. It only uses `a`, so it doesn't have to allocate again after the point a is defined. But #2 might allocate each time through the loop. (It currently doesn't, but this is filed as an open bug because it is supposed to.) Since it uses `b` which is defined inside the loop, it will have to allocate a new copy for each iteration.
 Is this function called every time when allocation happens in a 
 heap?
Not any allocation, it is just the function the compiler uses when it needs to make a closure.
Jun 17
next sibling parent ANtlord <antlord92 gmail.com> writes:
On Saturday, 17 June 2017 at 17:15:50 UTC, Adam D. Ruppe wrote:
 On Saturday, 17 June 2017 at 14:19:34 UTC, ANtlord wrote:
 Excuse me, I can't get what does it mean "deepest-referenced". 
 What the deep you mean? The deep of a closure or deep of the 
 function where the variable is defined. Can you give an 
 example code?
Where the variable is defined that is referenced in the closure. So: --- void uses(void delegate() dg); void foo() { int a; foreach(b; 0 .. 10) { uses( () { a++; } ); // #1 uses( () { b++; } ); // #2 } } --- In that case, #1 would only be allocated once, at the start of the foo() function. It only uses `a`, so it doesn't have to allocate again after the point a is defined. But #2 might allocate each time through the loop. (It currently doesn't, but this is filed as an open bug because it is supposed to.) Since it uses `b` which is defined inside the loop, it will have to allocate a new copy for each iteration.
 Is this function called every time when allocation happens in 
 a heap?
Not any allocation, it is just the function the compiler uses when it needs to make a closure.
Thanks a lot, Adam! Everything is clear. Except for the bug. I've got an expected result of a value of the variable from #2. The value equals to number from sequence plus one in each iteration. There are ten iterations. What's wrong? Are there should be five iterations? It doesn't make sense for me due to the variable assigned value from the sequence 0..10. Or do I look at the wrong place? Can you give me a link to the bug? Thank you again!
Jun 17
prev sibling parent reply Dsby <dushibaiyu yahoo.com> writes:
On Saturday, 17 June 2017 at 17:15:50 UTC, Adam D. Ruppe wrote:
 On Saturday, 17 June 2017 at 14:19:34 UTC, ANtlord wrote:
 [...]
Where the variable is defined that is referenced in the closure. So: [...]
if the uses parma is 'scope': void uses(scope void delegate() dg); will it be not alloc memory?
Jun 19
parent reply Dsby <dushibaiyu yahoo.com> writes:
On Monday, 19 June 2017 at 09:10:16 UTC, Dsby wrote:
 On Saturday, 17 June 2017 at 17:15:50 UTC, Adam D. Ruppe wrote:
 On Saturday, 17 June 2017 at 14:19:34 UTC, ANtlord wrote:
 [...]
Where the variable is defined that is referenced in the closure. So: [...]
if the uses parma is 'scope': void uses(scope void delegate() dg); will it be not alloc memory?
I test it , if use scope it will not alloc memony. import std.stdio; void call(void delegate() fun) { fun(); } void call2(scope void delegate() fun) { fun(); } void main() { int a = 10; // call((){writeln(a);}); call2((){writeln(a);}); } dmd -vgc ./t.d it will not print anything. if use call: void main() { int a = 10; call((){writeln(a);}); // call2((){writeln(a);}); } dmd -vgc ./t.d 182ms  2017年06月19日 星期一 17时16分47秒 ./t.d(13): vgc: using closure causes GC allocation
Jun 19
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 19 June 2017 at 09:18:56 UTC, Dsby wrote:
 void uses(scope void delegate() dg);

 will it be not alloc memory?
I test it , if use scope it will not alloc memony.
Right, using `scope` at the point the delegate variable is defined means it will never allocate.
Jun 19