6 ms·
I'm writing this comment in hope that Rust language designers read this thread. It's very important to language designers at this time to avoid stop-the-world
by mkup 15y ago
I'm writing this comment in hope that Rust language designers read this thread.
It's very important to language designers at this time to avoid stop-the-world GC approach in Rust at any cost.
Google Go is beautiful programming language, but its key limitation is stop-the-world approach to GC which makes it very difficult to implement highload web servers, DB engines and other software with strict max-time-to-response requirements. Recent research [1][2] suggests that "normal" Go program spends more time collecting garbage than performing actual calculations.
[1] https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf https://days2011.scala-lang.org/sites/days2011/files/ws3-1-H...
[2] http://www.theregister.co.uk/2011/07/01/go_v_cpluplus_redux/ http://www.theregister.co.uk/2011/07/01/go_v_cpluplus_redux/
Go programming language has gone too far to separate owning and non-owning pointers at syntactic level, to disallow changeable global variables, to enforce rules like "each mutable object is accessible from only one thread", and introduce other means to avoid GC.
But Rust is new and young, already has 2 types of pointers, and it could avoid GC by RAII and reference counting. Objects linked in cycles with owning pointers would cause memory leaks, and I think this behaviour may be left as is, kinda "it's not a bug, it's a feature". Weak pointers could point to intermediary descriptor which holds owning-refcount and nonowning-refcount. Weak ptr behaves like a NULL if owning-refcount is zero and target object is already destroyed. This is to guarantee safe memory model.
In short please take all means to avoid main Go defect "Garbage collection takes more CPU time than actual computations". Please avoid stop-the-world GC approach which makes the language almost useless for real applications.
- ori_b 15y agoThat's more that go has an incredibly crude GC (which is in the process of being replaced, as far as I know), and less that it is fundamentally broken. Other language and GC implementations with a large shared heap can work fine. See, for example, Azul systems' JVM.
- nickik 15y agoAzul systems GC has Hardware and OS support that you don't have normally but I do generally agree.
- ori_b 15y agoThey have x86 ports of their system as well, I believe.
- nickik 15y agoThis is not really correct. As far as I understand the run a virtualization layer ontop of x86 that provieds these features. On would think that this is not worth it but there JIT and GC are so much better that it is worth it. This however is not as easy to use as typing "ruby dostuff.rb" or something. You need to run a full virtuall OS. I do really really hope that Intel does these Hardware changes it would help ever language with GC. (The OS would need to support that too but thats probebly a easyer then getting intel to add the feature)
- modeless 15y agoReference counting is not the answer. It has too much overhead and cycles are a serious problem that shouldn't be swept under the rug. Real GC can be pauseless with the right language design and the proper use of virtual memory. I don't think any open source project is there yet, but there was a very interesting article a while back about the Azul JVM's approach.
- mkup 15y agoReference counting works just fine in Python and C++. If reference counter is thread-local (i.e. its increment/decrement is not done with InterlockedIncrement/Decrement = LOCK XADD/XSUB), then it won't cause a lot of MESI traffic and related memory I/O interlocks. And, as far as I can see, refcounting in Rust can be thread-local.
- pcwalton 15y agoYou'd be surprised how much overhead our reference counting has. 10% of the time of rustc, last I measured, was spent adjusting reference counts.
- mkup 15y agoIn Go, there's much larger overhead for GC. Russ Cox says in [2] (see link in my first comment above): We used gopprof to study an inefficient Go program and then to improve its performance by an order of magnitude and to reduce its memory usage by a factor of six. A subsequent comparison with an equivalently optimized C++ program shows that Go can be competitive with C++ when programmers are careful about how much garbage is generated by inner loops. They got a speedup about order of magnitude by improving memory management in the inner loops. So 10% of time for refcounting isn't that much. 90% of time for GC is much worse. Especially if it is a stop-the-world GC on 12-core server system. One core collects garbage, 11 cores just cool off.
- enneff 15y agoYour conclusion is flawed. We got an order of magnitude improvement by making a naively-constructed program efficient, and it was easy. That's hardly an indictment of Go's garbage collector. Also, the Go GC is a parallel GC which will use all cores during collection.
- pcwalton 15y agoGarbage collection in Rust is thread-local. We never need concurrent GC; this invariant is enforced by the type system. Leaking cycles is not really an option, sorry. At the very least we're going to have a cycle collector. It's too easy to make cycles, especially when you have closures (all you need is to close over an object that contains a pointer to the closure itself; this is very common for e.g. event handlers). Besides, a lot of the problems you state can be addressed with generational or incremental garbage collection.
- mkup 15y agoIf there is no difference on the syntactic level between owning and non-owning pointers, like in Go programming language, like in Python, then I agree with you - it's extremely easy to make a cycle. But if there's a difference between owning and non-owning pointer, then backlink to parent object in child object could be non-owning and other issues could handled in similar manner. Cycle detector which stops the program with references to the source code where the cycle was created - is a good idea, because in server systems under heavy load it just could be disabled. Basically it's a debugging tool, once it was proven by the testing that there are no bugs, these checks can be turned off in production. Like a C assertion checks.
- fanf2 15y agoThey are following the Erlang model, in which GC is per-thread only, and threads are small lightweight language-level creations. So a GC pause in one thread doesn't affect other threads in the program.
- mkup 15y agoIt would be nice if it could work that way in Rust. In Google Go garbage collector stops all heavyweight OS threads [See go/src/pkg/runtime/proc.c:runtimeВ·stoptheworld() in the source tree.]
- pcwalton 15y agoIt does indeed work that way in Rust. It's also intended that the GC be able to yield in the green thread sense as well, so it doesn't even lock up a core.
- supersillyus 15y agoI'm not sure that your premise is solid. Your citations point to a single program that was somewhat naively written, not well optimized, and designed as a computational benchmark spending much of it's time in GC. That's doesn't necessarily imply that "GC takes more CPU time than actual computations in normal Go programs". That's not to say that Go's GC isn't slow, but as citation #2 shows, one can limit heap allocation if performance requires it. So, the fact that you're saying "Don't do what Go does, it makes Go almost useless for real world applications" seems odd to be because: 1. Not all applications care deeply about stop-the-world gc pauses. 2. Not all of those that do will have a problem with them, as GC can be avoided by value semantics and escape analysis. 3. Go will not necessarily always have a Stop-The-World GC, though it does now. I don't think it's required by the spec. 4. People are using Go in real world applications, implying that it isn't almost useless. Even servers. 5. The Rust folks clearly have thought hard about efficient and scalable memory management, and the slideshow indicates that, so I'm not sure why you're worried for them.