Thread GC non "stop-the-world"
Oscar Martin via Digitalmars-d
digitalmars-d at puremagic.com
Mon Sep 22 17:15:51 PDT 2014
The cost of using the current GC in D, although beneficial for
many types of programs, is unaffordable for programs such as
games, etc... that need to perform repetitive tasks every short
periods of time. The fact that a GC.malloc/realloc on any thread
can trigger a memory collection that stop ALL threads of the
program for a variable time prevents it. Conversations in the
forum as "RFC: reference Counted Throwable", "Escaping the
Tyranny of the GC: std.rcstring, first blood" and the @nogc
attribute show that this is increasingly perceived as a problem.
Besides the ever-recurring "reference counting", many people
propose to improve the current implementation of GC. Rainer
Schuetze developed a concurrent GC in Windows:
http://rainers.github.io/visuald/druntime/concurrentgc.html
With some/a lot of work and a little help compiler (currently it
indicates by a flag if a class/structure contains
pointers/references to other classes/structures, it could
increase this support to indicate which fields are
pointers/references) we could implement a
semi-incremental-generational-copying GC-conservative like:
http://www.hboehm.info/gc/
or
http://www.ravenbrook.com/project/mps/
Being incremental, they try to minimize the "stop-the-world"
phase. But even with an advanced GC, as programs become more
complex and use more memory, pause time also increases. See for
example (I know it's not normal case, but in a few years ...)
http://blog.mgm-tp.com/2014/04/controlling-gc-pauses-with-g1-collector
(*) What if:
- It is forbidden for "__gshared" have references/pointers to
objects allocated by the GC (if the compiler can help with this
prohibition, perfect, if not the developer have to know what he
is doing)
- "shared" types are not allocated by the GC (they could be
reference counted or manually released or ...)
- "immutable" types are no longer implicitly "shared"
In short, the memory accessible from multiple threads is not
managed by the GC.
With these restrictions each thread would have its "I_Allocator",
whose default implementation would be an
incremental-generational-semi-conservative-copying GC, with no
inteference with any of the other program threads (it should be
responsible only for the memory reserved for that thread). Other
implementations of "I_Allocator" could be based on Andrei's
allocators. With "setThreadAllocator" (similar to current
gc_setProxy) you could switch between the different
implementations if you need. Threads with critical time
requirements could work with an implementation of "I_Allocator"
not based on the GC. It would be possible simulate scoped classes:
{
setThreadAllocator(I_Allocator_pseudo_stack)
scope(exit) {
I_Allocator_pseudo_stack.deleteAll();
setThreadAllocator(I_Allocator_gc);
}
auto obj = MyClass();
...
// Destructor are called and memory released
}
Obviously changes (*) break compatibility with existing code, and
therefore maybe they are not appropriate for D2. Also these are
general ideas, sure these changes lead to other problems. But the
point I want to convey is that in my opinion, while these
problems are solvable, a language for "system programming" is
incompatible with shared data managed by a GC
Thoughts?
More information about the Digitalmars-d
mailing list