Jump to page: 1 2 3
Thread overview
Per thread heap, GC, etc.
May 14, 2021
Markk
May 14, 2021
Markk
May 14, 2021
Markk
May 14, 2021
Imperatorn
May 14, 2021
Imperatorn
May 14, 2021
Imperatorn
May 14, 2021
Markk
May 14, 2021
Adam D. Ruppe
May 14, 2021
Markk
May 14, 2021
russhy
May 14, 2021
H. S. Teoh
May 14, 2021
Markk
May 14, 2021
russhy
May 15, 2021
sighoya
May 14, 2021
IGotD-
May 14, 2021
Imperatorn
May 14, 2021
Markk
May 14, 2021
IGotD-
May 14, 2021
Markk
May 14, 2021
H. S. Teoh
May 14, 2021
Markk
May 14, 2021
sighoya
May 14, 2021
Markk
May 14, 2021

Hi,

D has this nice default per-thread static memory model, i.e. if I understand all this correctly, this allows for better, more natural thread safety, while it makes it generally unsafe to use this memory from other threads (without locking). I guess the same is implicitly true for stack memory.

Now could it equally make sense to use per-thread heaps?

I.e. all allocations would need to be per thread, and it would be illegal to reference memory of one thread's heap, static memory, or stack from another thread's memory.

Some RAII locking could pin message-passed (etc.) references temporarily down for them to be used legally by another thread. This would make the sharing of the pointer known to the original thread for a strictly scoped time. Perhaps the synchronized keyword could be used for these stack references (just a spur of the moment proposal for the purpose of this discussion). Pinning is coupled with message-passing (etc.), i.e. no additional locking required.

For permanent change of ownership i.e. storing a reference in static or heap memory of the other thread, the referenced memory would have to be copied. I.e. there are no synchronized references from inside static or heap (i.e. non-stack, non-scoped) memory.

I guess synchronized class objects could get their own, non-thread specific, a.k.a. shared heap (similar in a way to the shared static memory). All stack references to synchronized class objects would have to be marked with synchronized too (or this might be inferred). synchronized class references stored in other (non-stack, non-scoped) thread memory would still be illegal.

Given the above, the GC could be run per thread. The world would not have to be stopped! Which means that some threads could entirely run without GC while others could still benefit from what I personally think is the only universal and scalable solution to memory safety. As a middle ground, some threads might only use a controlled amount of allocations, therefore GC runs would be super-fast, perhaps still acceptable under (near) real-time performance constrains.

The model would force developers towards a more modularized, per thread (service?) oriented architecture where message passing and lock free programming would be king... (said from a "schoolbook" understanding of these matters ;-)).

Also, I guess the performance of the resulting lock free heap allocs/frees, of the now (by language guarantee) lock free thread safe memory accesses, of the now per thread, smaller and (per definition) lock free GC runs etc. would improve.

Being per-thread i.e. non-preemptive, this could also simplify the GC and allow for more compiler optimizations, I guess. There is no danger of register aliasing and whatnot, that I can only guess makes preemptively interrupting GC correctness under high compiler optimization hard.

Just some thoughts after reading a handful Rust and D books... and after having seen so many wrinkle their noses at GC ... and therefore, unfortunately D.

_Mark

May 14, 2021

On Friday, 14 May 2021 at 13:48:12 UTC, Markk wrote:

>

Just some thoughts after reading a handful Rust and D books... and after having seen so many wrinkle their noses at GC ... and therefore, unfortunately D.

What do you think of per-task GC?

https://forum.dlang.org/post/yqdwgbzkmutjzfdhotst@forum.dlang.org

May 14, 2021

On Friday, 14 May 2021 at 14:14:32 UTC, Ola Fosheim Grøstad wrote:

>

On Friday, 14 May 2021 at 13:48:12 UTC, Markk wrote:

>

Just some thoughts after reading a handful Rust and D books... and after having seen so many wrinkle their noses at GC ... and therefore, unfortunately D.

What do you think of per-task GC?

https://forum.dlang.org/post/yqdwgbzkmutjzfdhotst@forum.dlang.org

I think the per thread-model could be one very powerful implementation method for your proposal. So the two don't contradict each other at all, at least as far as I understand.

However, the per-thread association does more than just introduce a new Allocator variant. It introduces language guarantees, mostly through the fact that there is a stack clearly associated per thread and therefore clear scoping is granted (this extends to fibers with a bit more complexity). The other rules for that guarantee are described above.

The proposal would be very "D", i.e. analog to the default thread local static data. In the same spirit as D's thread local static data, it addresses concurrency issues along with memory issues and therefore makes it simpler to code, simpler to implement (non-preemtive), plus more performant at the same time.

Personally, I think introducing explicit Allocators, i.e. chaining them through everything as (template) parameters or (worse) booby trapping with sneaky overloads, makes code much more complex, IMHO unbearably so.

For contrast, making memory management more of a per-thread thing, could solve this concern too. You can easily set an Allocator as a per thread setting and be done with it. The discussed language guarantees would make sure your allocations are not mixed or illegally referenced across. The exact same code can be run under different Allocators without template code bloat or parametrizing overhead.

When the thread terminates (or drops out of the defining scope), the whole memory can be freed as a whole. The discussed language guarantees would make sure you have nothing mixed and dangling. If GC was your set Allocator, no final collection is needed, as you equally proposed ;-).

_Mark

May 14, 2021

On Friday, 14 May 2021 at 13:48:12 UTC, Markk wrote:

>

Hi,

Just some thoughts after reading a handful Rust and D books... and after having seen so many wrinkle their noses at GC ... and therefore, unfortunately D.

_Mark

Interesting thoughts. Just a general question I've been trying to understand:
Why do you think ppl "wrinkle their noses at GC"? 🤔

I don't get it. GC 4 life!! 🎶☀️
(yes I know in what circumstances you can't use it)

May 14, 2021

On Friday, 14 May 2021 at 15:10:37 UTC, Imperatorn wrote:

>

On Friday, 14 May 2021 at 13:48:12 UTC, Markk wrote:

>

Hi,

Just some thoughts after reading a handful Rust and D books... and after having seen so many wrinkle their noses at GC ... and therefore, unfortunately D.

_Mark

Interesting thoughts. Just a general question I've been trying to understand:
Why do you think ppl "wrinkle their noses at GC"? 🤔

For low level programming in general:

  1. real time issues/performance
  2. unpredictable cleanup (finalization/RAII)
  3. higher memory consumption
  4. more challenging interop with other languages
  5. cannot be used in some execution contexts

For D specifically:

  1. freezing all GC threads
  2. no tracking of ownership-type in the type system
May 14, 2021

On Friday, 14 May 2021 at 15:16:55 UTC, Ola Fosheim Grøstad wrote:

>

On Friday, 14 May 2021 at 15:10:37 UTC, Imperatorn wrote:

>

On Friday, 14 May 2021 at 13:48:12 UTC, Markk wrote:

>

Hi,

Just some thoughts after reading a handful Rust and D books... and after having seen so many wrinkle their noses at GC ... and therefore, unfortunately D.

_Mark

Interesting thoughts. Just a general question I've been trying to understand:
Why do you think ppl "wrinkle their noses at GC"? 🤔

For low level programming in general:

  1. real time issues/performance
  2. unpredictable cleanup (finalization/RAII)
  3. higher memory consumption
  4. more challenging interop with other languages
  5. cannot be used in some execution contexts

For D specifically:

  1. freezing all GC threads
  2. no tracking of ownership-type in the type system

For low level I wouldn't even think of trying to use GC.

  1. Yeah, the implementation could be improved
May 14, 2021

On Friday, 14 May 2021 at 15:00:20 UTC, Markk wrote:

>

When the thread terminates (or drops out of the defining scope), the whole memory can be freed as a whole. The discussed language guarantees would make sure you have nothing mixed and dangling. If GC was your set Allocator, no final collection is needed, as you equally proposed ;-).

Yes, the problem is that spinning up a new thread is costly, and in order to get the benefits of "no final collection" the thread should be short lived.

So, that is where tasks come to the rescue. If you can split the work-load on many short-lived tasks then it can execute on many threads at the same time and still not cause any collection cycle.

Of course, if you allow suspension of execution then you need to deal with saving the stack somehow or implement stackless coroutines (or something similar).

Anyway, I am happy to see that we are on the same page in general, let's keep the ideas on this flowing :-). Then maybe we can come up with something nice over time.

Cheers,
Ola.

May 14, 2021

On Friday, 14 May 2021 at 15:10:37 UTC, Imperatorn wrote:

>

On Friday, 14 May 2021 at 13:48:12 UTC, Markk wrote:

>

Hi,

Just some thoughts after reading a handful Rust and D books... and after having seen so many wrinkle their noses at GC ... and therefore, unfortunately D.

_Mark

Interesting thoughts. Just a general question I've been trying to understand:
Why do you think ppl "wrinkle their noses at GC"? 🤔

I don't get it. GC 4 life!! 🎶☀️
(yes I know in what circumstances you can't use it)

First, I love the proposition of a GC. Most concerns are probably unfounded and ill-informed.

But look at even this forum. It seems to be one of the biggest no-gos for D. Some of that is justified, such as for near-realtime performance or embedded. Some of it is just driven by fashion-victim hypes around Rust (a terrible language) and others.

Why is it so important?

Mostly because it is an all-or-nothing proposition. Even one dependency (lib) can lock you in. AFAIK, you can't break out of it, even for parts of your application that - in themselves - don't use it.

The thread proposition would alleviate all these concerns. You could finally, truly have it both ways at the same time.

D is the only language that I know that comes this close!

_Mark

May 14, 2021

On Friday, 14 May 2021 at 15:23:13 UTC, Markk wrote:

>

But look at even this forum. It seems to be one of the biggest no-gos for D.

There's two types of programmer: the ones busy doing actual productive work and the ones with the spare time to complain about GC on the forum.

May 14, 2021

On Friday, 14 May 2021 at 15:21:30 UTC, Ola Fosheim Grøstad wrote:

>

On Friday, 14 May 2021 at 15:00:20 UTC, Markk wrote:

>

Yes, the problem is that spinning up a new thread is costly, and in order to get the benefits of "no final collection" the thread should be short lived.

I think thread pooling (along with the scoped release I described) and/or D's fibers address all of these concerns in very elegant ways.

Again, D is already very, very close.

_Mark

« First   ‹ Prev
1 2 3