February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Wednesday, 5 February 2014 at 20:18:33 UTC, Adam D. Ruppe wrote: > On Wednesday, 5 February 2014 at 19:39:43 UTC, Andrei Alexandrescu wrote: >> You do figure that complicates usage considerably, right? > > I don't see much evidence for that. Many, many newer modules in Phobos are currently allocation free yet still pretty easy to use. > > A major source of little allocations in my code is std.conv and std.string. But these aren't difficult to change to external allocation, in theory at least: > > string s = to!string(50); // GC allocates (I'd keep this for convenience and compatibility) > > char[16] buffer; > char[] s = toBuffer(buffer[], 50); // same thing, using a buffer > > char[] s = toLowerBuffer(buffer[], "FOO"); > assert(buffer.ptr is s); > assert(s == "foo"); > > > That's not hard to use (though remembering that s is a borrowed reference to a stack buffer might be - escape analysis is something we should really have). > > And it gives full control over both allocation and deallocation. It'd take some changes in phobos, but so does the RCSlice sooo yeah, and this actually decouples it from the GC. Yeah, because RCSlice would require changes to Phobos too I'd much rather have this approach because it is just so much more flexible and hardly adds any inconvenience. Combined with the upcoming allocators it would be incredibly powerful. You could have an output range that uses an allocator which stores on the stack unless it grows too big (and the stack size could be completely customizable by the user who knows best). Or you could pass in an output range that reference counts its memory. Or an output range that must remain unique and frees its contents when it goes out of scope. I think three things would work together really well for addressing users that want to avoid the GC while making use of Phobos. 1) Increasing the support for output ranges, 2) Andrei's slick allocator design, and 3) @nogc. With those three I really think managing memory and avoiding the GC will be rather pleasant. @nogc would enable people trying to avoid all the tough to spot implicit GC allocations to identify them easily. Once uncovered, they just switch to the output range version of a function in Phobos and they then use std.allocator with the output range they feed in to create an ideal allocation strategy for their use case (whether it stack, GC, scope freed heap, reference counted, a memory pool, or some hybrid of those). > The tricky part might be making it work with buffers, growable buffers, sink functions, etc., but we've solved similar problems with input ranges. > > >> I was thinking RCSlice would be a better alternative. > > I very rarely care about when little slices are freed. Large blocks of memory might be another story (I've used malloc+free for a big internal buffer in my png.d after getting memory leaks from false poitners with teh gc) but those can be handled on a case by case basis. std.base64 for example might make sense to return one of these animals. > > I don't have a problem with refcounting on principle but most the time, it just doesn't matter. |
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Wednesday, 5 February 2014 at 21:00:32 UTC, Adam D. Ruppe wrote:
> On Wednesday, 5 February 2014 at 20:46:32 UTC, Johannes Pfau wrote:
>> However, I wonder if that's really a problem in phobos. I'd guess most functions accepting slice input don't store a reference.
>> We should probably start documenting that. (Or finish 'scope' as you already said implicitly ;-).
>
> Aye. If the reference never escapes, it doesn't need to be counted or freed (indeed, it really MUST never be freed, since whomever passed you that reference may still be using it and is responsible for freeing it (or passing the buck to the GC))
I wonder if passing it in as "scope" could be utilized in some way to forgo reference count increments/decrements.
|
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Wednesday, 5 February 2014 at 21:00:32 UTC, Adam D. Ruppe wrote:
> On Wednesday, 5 February 2014 at 20:46:32 UTC, Johannes Pfau wrote:
>> However, I wonder if that's really a problem in phobos. I'd guess most functions accepting slice input don't store a reference.
>> We should probably start documenting that. (Or finish 'scope' as you already said implicitly ;-).
>
> Aye. If the reference never escapes, it doesn't need to be counted or freed (indeed, it really MUST never be freed, since whomever passed you that reference may still be using it and is responsible for freeing it (or passing the buck to the GC))
This. I think simply implementing scope will be much more important and effective step in optimizing D memory management model than current roadmap Andrei has posted recently. Simply because it enables non-breaking enhancements to Phobos that provide both allocation-free and safe functionality at the same time and is completely orthogonal to underlying allocation model.
|
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | tl; dr: it does not matter if this topic proposal works or not, it is simply an effort put into the wrong place |
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 2/5/2014 10:31 AM, Andrei Alexandrescu wrote:
> On 2/5/14, 12:03 AM, Nick Sabalausky wrote:
>> If that's so, then I'd think lib authors could easily provide APIs that
>> offer GC by default and ARC as an opt-in choice with templating:
>>
>> enum WantARC { Yes, No }
>> auto getFoo(WantARC arc = WantARC.No)() {
>> static if(arc == WantARC.No)
>> return getFoo().toGC();
>> else {
>> RCSlice!T x = ...;
>> return x;
>> }
>> }
>
> Nice. Though I'd say just return RC strings and let the client call
> toGC. They'd need to specify WantArc.No anyway so one way or another the
> user has to do something.
>
Note the default parameter of WantARC.No. Therefore:
// GC:
T[] fooGC = getFoo(); // Nothing special specified
// ARC:
RCSlice!T = getFoo!(WantARC.Yes)();
Or am I missing something?
|
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ola Fosheim Grøstad | On 2/5/14, 12:20 PM, "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang@gmail.com>" wrote: > On Wednesday, 5 February 2014 at 20:04:31 UTC, Andrei Alexandrescu wrote: >> I said it a couple of times, and it seems it bears repeating: the >> charter of this is solely to create a slice type that takes care of >> itself. What this is not is a general solution for managing internal >> pointers or pointers to arbitrary objects. > > Then I think this is starting in the wrong end of the problem space. > Slices are tiny dots in this picture. I'm confused. Slices are the bulkiest allocation there is: chunks of contiguous data. > It would be better to have a RC compiler switch and version{} statements > in the libraries rather than having extensive special casing of RC/GC > vs pure GC types in user code. I don't see where the extensive casing comes from. User code decides which way they want and they go for it. Simple aliases make certain decisions swappable. Andrei |
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | On 2/5/14, 12:23 PM, Michel Fortin wrote:
> On 2014-02-05 18:26:38 +0000, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> said:
>
>> On 2/5/14, 7:23 AM, Michel Fortin wrote:
>>> I don't think it makes much sense. ARC when used for D constructs should
>>> be treated an alternate GC algorithm, not a different kind of pointer.
>>
>> Why? The RC object has a different layout, so it may as well have a
>> different type.
>
> Well, it depends on your goal. If your goal is to avoid the garbage
> collector, you need all language constructs to use ARC. Having a single
> type in the language that relies on the GC defeats the purpose. What you
> want is simply to replace the current GC with another implantation, one
> that uses ARC. It shouldn't affect user code in any way, it's mostly an
> implementation detail (managed by the compiler and the runtime).
>
> If your goal is to have a deterministic lifetime for slices in some
> situations, then RCSlice as you proposes it is fine. That said, with a
> library type you'll have a hard time making the optimizer elide
> redundant increment/decrement pairs, so it'll never be optimal. I'm also
> not sure there's a lot of use cases for a deterministic slice lifetime
> working side by side with memory managed by the current GC.
>
> To me it seems you're trying to address a third problem here: that
> people have complained that Phobos relies on the GC too much. This comes
> from people who either don't want the GC to pause anything, or people
> who want to reduce memory allocations altogether. For the former group,
> replacing the current GC with an ARC+GC scheme at the language level,
> with the possibility to disable the GC, will fix most of Phobos (and
> most other libraries) with no code change required. For the later group,
> you need to make the API so that allocations are either not necessary,
> or when necessary provide a way to use a custom an allocator of some sort.
I want to make one positive step toward improving memory allocation in the D language.
Andrei
|
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dmitry Olshansky | On 2/5/14, 12:35 PM, Dmitry Olshansky wrote:
> 05-Feb-2014 03:51, Andrei Alexandrescu пишет:
>> Consider we add a library slice type called RCSlice!T. It would have the
>> same primitives as T[] but would use reference counting through and
>> through. When the last reference count is gone, the buffer underlying
>> the slice is freed. The underlying allocator will be the GC allocator.
>>
>> Now, what if someone doesn't care about the whole RC thing and aims at
>> convenience? There would be a method .toGC that just detaches the slice
>> and disables the reference counter (e.g. by setting it to uint.max/2 or
>> whatever).
>>
>> Then people who want reference counting say
>>
>> auto x = fun();
>
> How abut just adding a template argument that indicates which container
> type to use for internal allocation?
>
> Array!T a = fun!(Array)(); //Ref-counted
> T[] a = fun(); //default args - GC
>
> IMHO solves Phobos side of equation.
Good idea.
Andrei
|
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On 2/5/14, 1:10 PM, Dicebot wrote:
> tl; dr: it does not matter if this topic proposal works or not, it is
> simply an effort put into the wrong place
Noted. On the face of it it seems odd that reference counted chunks of typed memory are deemed useless, at the tail of a discussion discussing in great detail the important advantages of reference counting. I should also add that imparting useful semantics to scope is much more difficult than it might seem. In contrast, reference counted slices are realizable in the current language with a relatively small (scoped! :o)) library effort and can be put to use immediately. I see a lot of good reasons to add them to Phobos regardless of the larger memory allocation changes we plan to make.
Andrei
|
February 05, 2014 Re: Idea #1 on integrating RC with GC | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Wednesday, 5 February 2014 at 22:18:33 UTC, Andrei Alexandrescu wrote:
> I'm confused. Slices are the bulkiest allocation there is: chunks of contiguous data.
IMHO there should be one highly optimized low level ref-count structure that works everywhere, has compiler support and has an attractive syntax. That seems to be the most obvious solution.
If not you might as well write your own array implementation, with better performance for your domain, or use an existing C++ framework that is geared towards your application domain.
If we are talking games and simulation then you probably have your own allocator for search data structures (engine level) which are kind of fixed, predictable, tuneable, highly optimized, and uniquely owned. You allocate more, but probably seldom release.
What is allocated/deallocated is "scripty" evolutionary stuff (content level). Dynamic game-world stuff that come in all kind of shapes and sizes: enemies, weapons, cars, events etc. Objects and their shifty relationships. 100.000+ objects for a game server. Stuff that is heterogeneous and is constantly modified in order to improve game play.
|
Copyright © 1999-2021 by the D Language Foundation