Discussion:
More radical ideas about gc and reference counting
(too old to reply)
Andrei Alexandrescu via Digitalmars-d
2014-04-30 20:21:33 UTC
Permalink
Walter and I have had a long chat in which we figured our current
offering of abstractions could be improved. Here are some thoughts.
There's a lot of work ahead of us on that and I wanted to make sure
we're getting full community buy-in and backup.

First off, we're considering eliminating destructor calls from within
the GC entirely. It makes for a faster and better GC, but the real
reason here is that destructors are philosophically bankrupt in a GC
environment. I think there's no need to argue that in this community.
The GC never guarantees calling destructors even today, so this decision
would be just a point in the definition space (albeit an extreme one).

That means classes that need cleanup (either directly or by having
fields that are structs with destructors) would need to garner that by
other means, such as reference counting or manual. We're considering
deprecating ~this() for classes in the future.

Also, we're considering a revamp of built-in slices, as follows. Slices
of types without destructors stay as they are.

Slices T[] of structs with destructors shall be silently lowered into
RCSlice!T, defined inside object.d. That type would occupy THREE words,
one of which being a pointer to a reference count. That type would
redefine all slice primitives to update the reference count accordingly.

RCSlice!T will not convert implicitly to void[]. Explicit cast(void[])
will be allowed, and will ignore the reference count (so if a void[]
extracted from a T[] via a cast outlives all slices, dangling pointers
will ensue).

I foresee any number of theoretical and practical issues with this
approach. Let's discuss some of them here.


Thanks,

Andrei
Vladimir Panteleev via Digitalmars-d
2014-04-30 20:31:01 UTC
Permalink
On Wednesday, 30 April 2014 at 20:21:33 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu via Digitalmars-d
Walter and I have had a long chat in which we figured our
current offering of abstractions could be improved. Here are
some thoughts. There's a lot of work ahead of us on that and I
wanted to make sure we're getting full community buy-in and
backup.
First off, we're considering eliminating destructor calls from
within the GC entirely. It makes for a faster and better GC,
but the real reason here is that destructors are
philosophically bankrupt in a GC environment. I think there's
no need to argue that in this community. The GC never
guarantees calling destructors even today, so this decision
would be just a point in the definition space (albeit an
extreme one).
An extreme one indeed, it would break a lot of my code. Every D
project I wrote that does networking manages memory using a class
that resides on the managed heap, but holds the actual wrapped
data in the unmanaged heap. It has a number of advantages over
other approaches, and I've posted it to the announce group, but
the idea didn't seem to catch on.

https://github.com/CyberShadow/ae/blob/master/sys/data.d

I could migrate the concept to use reference counting (it was
implemented in D1, before reference counting was possible), but
that's my situation regarding breaking existing code.
Andrei Alexandrescu via Digitalmars-d
2014-04-30 20:45:58 UTC
Permalink
Post by Andrei Alexandrescu via Digitalmars-d
Walter and I have had a long chat in which we figured our current
offering of abstractions could be improved. Here are some thoughts.
There's a lot of work ahead of us on that and I wanted to make sure
we're getting full community buy-in and backup.
First off, we're considering eliminating destructor calls from within
the GC entirely. It makes for a faster and better GC, but the real
reason here is that destructors are philosophically bankrupt in a GC
environment. I think there's no need to argue that in this community.
The GC never guarantees calling destructors even today, so this
decision would be just a point in the definition space (albeit an
extreme one).
An extreme one indeed, it would break a lot of my code. Every D project
I wrote that does networking manages memory using a class that resides
on the managed heap, but holds the actual wrapped data in the unmanaged
heap.
So should I take it those classes all have destructors? -- Andrei
Vladimir Panteleev via Digitalmars-d
2014-04-30 20:57:23 UTC
Permalink
On Wednesday, 30 April 2014 at 20:45:57 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu via Digitalmars-d
Post by Vladimir Panteleev via Digitalmars-d
An extreme one indeed, it would break a lot of my code. Every
D project
I wrote that does networking manages memory using a class that resides
on the managed heap, but holds the actual wrapped data in the
unmanaged
heap.
So should I take it those classes all have destructors? --
One class, many instances (one for every chunk of data sent or
received).
Andrei Alexandrescu via Digitalmars-d
2014-04-30 20:59:35 UTC
Permalink
Post by Andrei Alexandrescu via Digitalmars-d
An extreme one indeed, it would break a lot of my code. Every D project
I wrote that does networking manages memory using a class that resides
on the managed heap, but holds the actual wrapped data in the unmanaged
heap.
So should I take it those classes all have destructors? --
One class, many instances (one for every chunk of data sent or received).
The question is, how comfortable are you with today's reality that some
of those instances may be never destroyed? -- Andrei
Vladimir Panteleev via Digitalmars-d
2014-04-30 21:05:47 UTC
Permalink
On Wednesday, 30 April 2014 at 20:59:34 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu via Digitalmars-d
Post by Vladimir Panteleev via Digitalmars-d
On Wednesday, 30 April 2014 at 20:45:57 UTC, Andrei
Post by Andrei Alexandrescu via Digitalmars-d
Post by Vladimir Panteleev via Digitalmars-d
An extreme one indeed, it would break a lot of my code.
Every D project
I wrote that does networking manages memory using a class
that resides
on the managed heap, but holds the actual wrapped data in
the unmanaged
heap.
So should I take it those classes all have destructors? --
One class, many instances (one for every chunk of data sent or received).
The question is, how comfortable are you with today's reality
that some of those instances may be never destroyed? -- Andrei
I'm fine with it. The proxy objects are purposefully as small as
possible, to make false references (and thus, memory leaks)
unlikely, even on 32 bits. If I was concerned with it, I'd have
switched to reference counting as soon as it was possible.
Timon Gehr via Digitalmars-d
2014-04-30 20:57:45 UTC
Permalink
Post by Andrei Alexandrescu via Digitalmars-d
An extreme one indeed, it would break a lot of my code. Every D project
I wrote that does networking manages memory using a class that resides
on the managed heap, but holds the actual wrapped data in the unmanaged
heap.
So should I take it those classes all have destructors? -- Andrei
(Yes, those destructors free the unmanaged memory.)
Andrei Alexandrescu via Digitalmars-d
2014-04-30 21:00:31 UTC
Permalink
Post by Timon Gehr via Digitalmars-d
Post by Andrei Alexandrescu via Digitalmars-d
An extreme one indeed, it would break a lot of my code. Every D project
I wrote that does networking manages memory using a class that resides
on the managed heap, but holds the actual wrapped data in the unmanaged
heap.
So should I take it those classes all have destructors? -- Andrei
(Yes, those destructors free the unmanaged memory.)
Thanks... that would need to change :o). -- Andrei
monarch_dodra via Digitalmars-d
2014-04-30 20:33:16 UTC
Permalink
On Wednesday, 30 April 2014 at 20:21:33 UTC, Andrei Alexandrescu
We're considering deprecating ~this() for classes in the future.
[...]
Slices T[] of structs with destructors shall be silently
lowered into RCSlice!T, defined inside object.d
I'm sure instead of outright deprecating destructor for class, we
could just store them in a RCClass!C (which would be 2 words big).

If you can get the scheme working with slices of structs with
destructors, I don't see why the same scheme couldn't work with
Class'es too.
Andrei Alexandrescu via Digitalmars-d
2014-04-30 20:47:03 UTC
Permalink
We're considering deprecating ~this() for classes in the future.
[...]
Slices T[] of structs with destructors shall be silently lowered into
RCSlice!T, defined inside object.d
I'm sure instead of outright deprecating destructor for class, we could
just store them in a RCClass!C (which would be 2 words big).
That's an interesting idea, but the whole notion of converting to Object
etc. makes the concept difficult (unless we define another root etc).

Andrei
deadalnix via Digitalmars-d
2014-04-30 20:46:15 UTC
Permalink
On Wednesday, 30 April 2014 at 20:21:33 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu via Digitalmars-d
Walter and I have had a long chat in which we figured our
current offering of abstractions could be improved. Here are
some thoughts. There's a lot of work ahead of us on that and I
wanted to make sure we're getting full community buy-in and
backup.
Still no consideration for isolated.
Post by Andrei Alexandrescu via Digitalmars-d
First off, we're considering eliminating destructor calls from
within the GC entirely. It makes for a faster and better GC,
but the real reason here is that destructors are
philosophically bankrupt in a GC environment. I think there's
no need to argue that in this community. The GC never
guarantees calling destructors even today, so this decision
would be just a point in the definition space (albeit an
extreme one).
That means classes that need cleanup (either directly or by
having fields that are structs with destructors) would need to
garner that by other means, such as reference counting or
manual. We're considering deprecating ~this() for classes in
the future.
Not sure how I feel about that. This has been proposed as a
solution to some GC issue at last DConf and has been dismissed.
Your post is unclear on why this decision has changed. There must
be some new information or data that inform this decision.

Or is it random ?

Also, what about cycle in RC things ? Also, RC is good on top of
GC, so you can collect loop, especially if we are going to RC
automagically. That is a major issue.

Finally, immutable is sharable accross thread. That mean, even if
we bypass the type system, that RC must be atomic for immutable.
As they convert automatically for co,st, that mean that all const
code will be full of atomic increment/decrement. They are bad for
the CPU, and cannot be optimized away.

That mean we are back to having a const and a mutable version of
functions for performance reasons.
Post by Andrei Alexandrescu via Digitalmars-d
Also, we're considering a revamp of built-in slices, as
follows. Slices of types without destructors stay as they are.
Slices T[] of structs with destructors shall be silently
lowered into RCSlice!T, defined inside object.d. That type
would occupy THREE words, one of which being a pointer to a
reference count. That type would redefine all slice primitives
to update the reference count accordingly.
RCSlice!T will not convert implicitly to void[]. Explicit
cast(void[]) will be allowed, and will ignore the reference
count (so if a void[] extracted from a T[] via a cast outlives
all slices, dangling pointers will ensue).
This won't work. array have a lot of magic that cannot be created
as library. ie:

RCSlice!(const T) has nothing to do with const(RCSlice!T) as far
as the compiler is concerned.

This is why we still don't have any library that provides
collection properly. One of the best is probably dcollection, and
it has no solution for that problem.

I'd like to see some core issue like that one before changing
everything on top of it. When the whole thing is built on goo,
readjusting the top to make it point upward is doomed to create
the Pisa tower. Fine for tourists, but not very practical nor
useful.
Andrei Alexandrescu via Digitalmars-d
2014-04-30 20:49:31 UTC
Permalink
Post by deadalnix via Digitalmars-d
Still no consideration for isolated.
https://github.com/D-Programming-Language/dmd/pull/3452 may be of
interest to you. -- Andrei
deadalnix via Digitalmars-d
2014-04-30 20:57:02 UTC
Permalink
On Wednesday, 30 April 2014 at 20:49:30 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu via Digitalmars-d
Post by deadalnix via Digitalmars-d
Still no consideration for isolated.
https://github.com/D-Programming-Language/dmd/pull/3452 may be
of interest to you. -- Andrei
I already commented on past similar proposal. These are piling up
more and more hacks to achieve roughly the same thing, badly.
This makes it impossible to provide a 3rd party implementation
that is compliant, is guaranteed to ends up in a nightmarish
explosion of special cases, or to be vastly underpowered.
Andrei Alexandrescu via Digitalmars-d
2014-04-30 20:57:26 UTC
Permalink
Post by deadalnix via Digitalmars-d
Post by Andrei Alexandrescu via Digitalmars-d
That means classes that need cleanup (either directly or by having
fields that are structs with destructors) would need to garner that by
other means, such as reference counting or manual. We're considering
deprecating ~this() for classes in the future.
Not sure how I feel about that.
"Ecstatic" is what you're looking for.
Post by deadalnix via Digitalmars-d
This has been proposed as a solution to
some GC issue at last DConf and has been dismissed. Your post is unclear
on why this decision has changed. There must be some new information or
data that inform this decision.
Or is it random ?
I don't remember a proposal being made that made slices of structs with
destructors distinct from other slices.
Post by deadalnix via Digitalmars-d
Also, what about cycle in RC things?
Resource leaks may happen in programs in any language. I'm prepared to
allow leaks in certain cases, and I posit here that such cases are rare
(arrays of objects that embed references to the very array they're in).
Post by deadalnix via Digitalmars-d
Also, RC is good on top of GC, so
you can collect loop, especially if we are going to RC automagically.
That is a major issue.
That stays, and it's useful. I'm talking destructors here.
Post by deadalnix via Digitalmars-d
Finally, immutable is sharable accross thread. That mean, even if we
bypass the type system, that RC must be atomic for immutable.
As they
convert automatically for co,st, that mean that all const code will be
full of atomic increment/decrement. They are bad for the CPU, and cannot
be optimized away.
Good point. I see that as a problem, albeit a solvable one.
Post by deadalnix via Digitalmars-d
That mean we are back to having a const and a mutable version of
functions for performance reasons.
I don't think that's the case. We could and should be able to only use
refcounting for truly immutable slices. (Using a bit in the counter to
indicate sharing comes to mind.)
Post by deadalnix via Digitalmars-d
Post by Andrei Alexandrescu via Digitalmars-d
RCSlice!T will not convert implicitly to void[]. Explicit cast(void[])
will be allowed, and will ignore the reference count (so if a void[]
extracted from a T[] via a cast outlives all slices, dangling pointers
will ensue).
This won't work. array have a lot of magic that cannot be created as
RCSlice!(const T) has nothing to do with const(RCSlice!T) as far as the
compiler is concerned.
We need to improve the language to allow for such. Did I mention it's
not going to be easy?


Andrei
deadalnix via Digitalmars-d
2014-04-30 21:24:14 UTC
Permalink
On Wednesday, 30 April 2014 at 20:57:26 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu via Digitalmars-d
"Ecstatic" is what you're looking for.
Probably...
Post by Andrei Alexandrescu via Digitalmars-d
Post by deadalnix via Digitalmars-d
This has been proposed as a solution to
some GC issue at last DConf and has been dismissed. Your post
is unclear
on why this decision has changed. There must be some new
information or
data that inform this decision.
Or is it random ?
I don't remember a proposal being made that made slices of
structs with destructors distinct from other slices.
So the RC slice thing is what make all that worthwhile ?
Post by Andrei Alexandrescu via Digitalmars-d
Post by deadalnix via Digitalmars-d
Also, RC is good on top of GC, so
you can collect loop, especially if we are going to RC
automagically.
That is a major issue.
That stays, and it's useful. I'm talking destructors here.
Then the RCSlice do not provide any guarantee at all.
Post by Andrei Alexandrescu via Digitalmars-d
Post by deadalnix via Digitalmars-d
Post by Andrei Alexandrescu via Digitalmars-d
RCSlice!T will not convert implicitly to void[]. Explicit
cast(void[])
will be allowed, and will ignore the reference count (so if a void[]
extracted from a T[] via a cast outlives all slices, dangling pointers
will ensue).
This won't work. array have a lot of magic that cannot be
created as
RCSlice!(const T) has nothing to do with const(RCSlice!T) as
far as the
compiler is concerned.
We need to improve the language to allow for such. Did I
mention it's not going to be easy?
If I understand what you mentioned, RCSlice is what make to you
the ditching of destructor worthwhile. The fact that this is not
doable in current D should be a showstopper for this whole thread
as all that is discussed here is dependent of what solution we
choose for this problem (right now we have none).

Timon Gehr via Digitalmars-d
2014-04-30 20:56:53 UTC
Permalink
Post by Andrei Alexandrescu via Digitalmars-d
Walter and I have had a long chat in which we figured our current
offering of abstractions could be improved. Here are some thoughts.
There's a lot of work ahead of us on that and I wanted to make sure
we're getting full community buy-in and backup.
First off, we're considering eliminating destructor calls from within
the GC entirely. It makes for a faster and better GC, but the real
reason here is that destructors are philosophically bankrupt in a GC
environment. I think there's no need to argue that in this community.
The GC never guarantees calling destructors even today, so this decision
would be just a point in the definition space (albeit an extreme one).
That means classes that need cleanup (either directly or by having
fields that are structs with destructors) would need to garner that by
other means, such as reference counting or manual. We're considering
deprecating ~this() for classes in the future.
...
struct S{
~this(){ /* ... */ }
/* ... */
}

class C{
S s;
}

?
Post by Andrei Alexandrescu via Digitalmars-d
Also, we're considering a revamp of built-in slices, as follows. Slices
of types without destructors stay as they are.
Slices T[] of structs with destructors shall be silently lowered into
RCSlice!T, defined inside object.d. That type would occupy THREE words,
one of which being a pointer to a reference count. That type would
redefine all slice primitives to update the reference count accordingly.
RCSlice!T will not convert implicitly to void[]. Explicit cast(void[])
will be allowed, and will ignore the reference count (so if a void[]
extracted from a T[] via a cast outlives all slices, dangling pointers
will ensue).
I foresee any number of theoretical and practical issues with this
approach. Let's discuss some of them here.
...
struct S{
~this(){ /* ... */ }
}

class C{
S[] s;
this(S[] s){ /* ... */ }
}

void main(){
new C(buildSs());
// memory leak
}

Also, cycles.
Andrei Alexandrescu via Digitalmars-d
2014-04-30 20:58:37 UTC
Permalink
Post by Timon Gehr via Digitalmars-d
struct S{
~this(){ /* ... */ }
/* ... */
}
class C{
S s;
}
?
By hand, as I mentioned. -- Andrei
Timon Gehr via Digitalmars-d
2014-04-30 21:09:47 UTC
Permalink
Post by Andrei Alexandrescu via Digitalmars-d
Post by Timon Gehr via Digitalmars-d
struct S{
~this(){ /* ... */ }
/* ... */
}
class C{
S s;
}
?
By hand, as I mentioned. -- Andrei
I meant, is it going to be deprecated too?
Andrei Alexandrescu via Digitalmars-d
2014-04-30 21:13:32 UTC
Permalink
Post by Timon Gehr via Digitalmars-d
Post by Andrei Alexandrescu via Digitalmars-d
Post by Timon Gehr via Digitalmars-d
struct S{
~this(){ /* ... */ }
/* ... */
}
class C{
S s;
}
?
By hand, as I mentioned. -- Andrei
I meant, is it going to be deprecated too?
No, that will continue to be allowed. -- Andrei
H. S. Teoh via Digitalmars-d
2014-04-30 21:15:50 UTC
Permalink
Post by Andrei Alexandrescu via Digitalmars-d
Post by Timon Gehr via Digitalmars-d
Post by Andrei Alexandrescu via Digitalmars-d
Post by Timon Gehr via Digitalmars-d
struct S{
~this(){ /* ... */ }
/* ... */
}
class C{
S s;
}
?
By hand, as I mentioned. -- Andrei
I meant, is it going to be deprecated too?
No, that will continue to be allowed. -- Andrei
Then what is it going to do? S.~this will never get called?


T
--
Never wrestle a pig. You both get covered in mud, and the pig likes it.
Continue reading on narkive:
Loading...