digitalmars.D - delegates and heap usage
- Franciszek Czekala (28/28) Dec 01 2010 What part of stack frame is exactly copied when a delegate is used? For
- Simen kjaeraas (29/38) Dec 01 2010 Generally, only the used variables.
- Franciszek Czekala (5/5) Dec 01 2010 I am not sure that this is a correct answer. 1600 bytes is just 100x2x8 ...
- Simen kjaeraas (20/29) Dec 01 2010 Wrong. The delegates would be 100x2x4 bytes, as DMD only produces 32-bit
What part of stack frame is exactly copied when a delegate is used? For example what is the heap usage due to delegates usage in the following code? The library reference speaks about the enclosing function but I do not think that it suffices to copy the stack frame of the directly enclosing function. Is the whole stack copied? What happens in the case of recursive calls? import std.stdio; void main(){ int x = 0; alias void delegate () del_t ; auto dlg = new del_t[100] ; void f(int n){ if (n<0) return; int y = n; int[1000] arr; void g(){ x++; void h(){ writeln(y,' ',x); } dlg[n] = &h; writeln("assigned, ", n); } g(); f(n-1); } f(99); for(int i = 0; i<100; i++) dlg[i](); }
Dec 01 2010
Franciszek Czekala <home valentimex.com> wrote:What part of stack frame is exactly copied when a delegate is used?Generally, only the used variables. You can check the size of the closure's stack copy using GC.sizeOf(dg.ptr).For example what is the heap usage due to delegates usage in the following code?Adding this code to the end of it: int n = 0; void* ptr = null; foreach ( e; dlg ) { if ( e.ptr != ptr ) { ptr = e.ptr; n += GC.sizeOf( e.ptr ); } } writeln( n ); We can see that 1600 bytes are used.The library reference speaks about the enclosing function but I do not think that it suffices to copy the stack frame of the directly enclosing function. Is the whole stack copied?All enclosing functions need to have their stack frames copied. That is, not the whole stack, but any functions for which the delegate would be a nested function.What happens in the case of recursive calls?int recurse( int delegate() dg ) { int n = 1; return GC.sizeOf( dg.ptr ) + ( dg() ? recurse( { return dg() - n; } ) : 0 ); } void main(){ writeln( recurse( { return 100; } ) ); } Outputs 1600. -- Simen
Dec 01 2010
I am not sure that this is a correct answer. 1600 bytes is just 100x2x8 bytes. Since delegates are fat (double) pointers this is probably just the memory occupied by dlg variables themselves, not the memory to which they point. Indeed adding an extra z variable in my code to the g() function and using it in writeln does not change the output: it is still 1600 bytes.
Dec 01 2010
Franciszek Czekala <home valentimex.com> wrote:I am not sure that this is a correct answer. 1600 bytes is just 100x2x8 bytes. Since delegates are fat (double) pointers this is probably just the memory occupied by dlg variables themselves, not the memory to which they point. Indeed adding an extra z variable in my code to the g() function and using it in writeln does not change the output: it is still 1600 bytes.Wrong. The delegates would be 100x2x4 bytes, as DMD only produces 32-bit exes. The 16 bytes per delegate is because that's the smallest block the GC will allocate. Proof: long recurse( long delegate() dg ) { long n = 1; long m = 0; long r = 0; long s = 0; long t = 0; return GC.sizeOf( dg.ptr ) + ( dg() ? recurse( { return dg() - n + m - r + s + t; } ) : 0 ); } void main(){ writeln( recurse( { return 100L; } ) ); } Outputs 6400. -- Simen
Dec 01 2010