On Phobos GC hunt

Dmitry Olshansky via Digitalmars-d digitalmars-d at puremagic.com
Wed Oct 8 05:08:59 PDT 2014


On Wednesday, 8 October 2014 at 11:25:25 UTC, Johannes Pfau wrote:
> Am Tue, 07 Oct 2014 15:57:58 +0000
> schrieb "Dmitry Olshansky" <dmitry.olsh at gmail.com>:
>
>> 
>> Instead we need to observe patterns and label it automatically 
>> until the non-trivial subset remains. So everybody, please 
>> take time and identify simple patterns and post back your 
>> ideas on solution(s).
>> 
>
> I just had a look at all closure allocations and identified 
> these
> patterns:

Awesome! This is exactly the kind of help I wanted.

>
>
> 1) Fixable by manually stack-allocating closure
>    A delegate is passed to some function which stores this 
> delegate and
>    therefore correctly doesn't mark the parameter as scope. 
> However,
>    the lifetime of the stored delegate is still limited to the 
> current
>    function (e.g. it's stored in a struct instance, but on the 
> stack).
>
>    Can be fixed by creating a static struct{T... members; void
>    doSomething(){access members}} instance on stack and passing
>    &stackvar.doSomething as delegate.

Hm... Probably we can create a template for this.

>
> 2) Using delegates to add state to ranges
>    ----
>    return iota(dim).
>      filter!(i => ptr[i])().
>      map!(i => BitsSet!size_t(ptr[i], i * bitsPerSizeT))().
>      joiner();
>    ----
>    This code adds state to ranges without declaring a new type: 
> the ptr
>    variable is not accessible and needs to be move into a 
> closure.
>    Declaring a custom range type is a solution, but not
>    straightforward: If the ptr field is moved into the range a 
> closure
>    is not necessary. But if the range is copied, it's address 
> changes
>    and the delegate passed to map is now invalid.
>

Indeed, such code is fine in "user-space" but have no place in 
the library.

> 3) Functions taking delegates as generic parameters
>    receiveTimeout,receive,formattedWrite accept different types,
>    including delegates. The delegates can all be scope to avoid 
> the
>    allocation but is void foo(T)(scope T) a good idea? The 
> alternative
>    is probably making an overload for delegates with scope 
> attribute.
>
>    (The result is that all functions calling receiveTimeout,... 
> with a
>    delegate allocate a closure)
>
> 4) Solvable with manual memory management
>    Some specific functions can't be easily fixed, but the 
> delegates
>    they create have a well defined lifetime (for example spawn 
> creates
>    a delegate which is only needed at the startup of a new 
> thread, it's
>    never used again). These could be malloc+freed.
>

I think this and (2) can be solved if we come up with solid 
support for RC-closures.

> 5) Design issue
>    These functions generally create a delegate using variables 
> passed
>    in as parameters. There's no way to avoid closures here. 
> Although
>    manual allocation is an possible, the lifetime is undefined 
> and can
>    only be managed by the GC.
>
> 6) Other
>    Two cases can be fixed by moving a buffer into a struct or 
> moving a
>    function out of a member function into it's surrounding 
> class.
>

Yeah, there are always outliers ;)

> Also notable: 17 out of 35 cases are in std.net.curl. This is 
> because
> curl heavily uses delegates and wrapper delegates.

Interesting... it must be due to cURL callback-based API.
All in all, std.net.curl is a constant source of complaints, it 
may need some work to fix other issues anyway.



More information about the Digitalmars-d mailing list