Discussion Thread: DIP 1028--Make @safe the Default--Final Review
Joseph Rushton Wakeling
joseph.wakeling at webdrake.net
Tue Mar 31 21:26:41 UTC 2020
On Monday, 30 March 2020 at 18:12:03 UTC, Steven Schveighoffer
wrote:
> Sociomantic avoids unpredictable GC cycles, but doesn't disable
> it (they still allow collections periodically IIRC). And they
> are built to be as fast as possible.
There were apps where a single GC cycle was not really an option,
because even a small GC pause would delay our responding to
requests where we couldn't afford the delay. But the solution
was not really _that_ hard: be strict about using recyclable
buffers and object pools, preallocate in advance so that there
would be minimal resizing ... and then be really strict about
keeping that policy.
There's no reason Discord couldn't have done that with their Go
app, but if I understood their blog post right, Go's GC
force-activates a cycle every 2 minutes regardless of whether any
new allocation has actually happened. (TBH I do wonder if this
is really _really_ true, or whether they were just generating
sufficient garbage to ensure this happened, despite their claims
of efficiency.)
But in any case Sociomantic could rely on the fact that in a D
app no new allocations means no chance to trigger a GC cycle
(which of course is why we preallocated as well as recycling
buffers and objects: ideally, we wanted no heap allocation after
app startup).
However, it was only a few apps where this was really necessary.
In fact I think a lot of the time we were much more strict about
preallocation and reusable buffers than we needed to be, and the
strictness was more of a hangover from working around historical
bugs that occurred when using 32-bit DMD.
Basically, the _other_ problem that arose in Sociomantic's use
case was that if you want to keep a given app running
indefinitely on the same server (and there were some apps that we
never wanted to restart if we didn't absolutely have to for new
deployments), then you really, really want to be sure that its
long term memory usage is stable. A small daily growth can add
up to a lot over months, and wind up bringing down the app or the
server. And in the early days, what they found was that if they
generated garbage, then slowly, over time, the memory usage would
creep up and up ... so they instigated this strong "preallocate
and reuse" policy to work around it.
When I was fairly new in the company I got the chance to
implement a new app, and quite early on my team lead sat down
with me to show me how to implement and validate the
prellocate-and-recycle way of doing things. The use-case meant
that it was unlikely there would be a problem if we had a GC
pause, and we wanted to iterate fast on this app, so I suggested
we make the code simpler and just rely on the GC. He explained
the long-term memory leak issue, but we agreed to let me try and
observe to see what happened. And it turned out that no
garbage-based memory leak emerged. Which was a nice surprise for
my lead and all the other old lags in the R&D team.
I don't think anybody ever did work out exactly what the problem
had been in the early days, but it's likely relevant that by the
time I broke the rules, the company had been using 64-bit DMD for
a long time. IIRC what was suspected (N.B. this is from memory
and from someone who is not an expert on the internals of the
GC:-) was that with the 32-bit GC there was something about the
size of GC pools or memory chunks that meant that it was very
likely that you could wind up with a chunk of GC memory where all
of it was in principle recyclable except for a couple of bytes,
and hence you would allocate new chunks and then the same thing
would happen with them, and so on until you were using far more
chunks than should really have been needed.
So, either in 64-bit DMD that didn't happen, or whatever GC bug
it was had long been fixed anyway. And once that discovery was
clearly established, I think we started relaxing the strictness a
bit in apps that didn't need to care about GC pauses.
The team that grew out of the app I was working on never did have
to really care about GC issues, but ironically I did wind up
rewriting that same app to make a lot more use of recyclable
buffers, though not preallocation. I don't recall that it was
ever really _necessary_, though: it was more of a precaution to
try and ensure the same memory consumption for D1 and D2 builds
of the same app, given that D2's GC seemed happy to allocate a
lot more memory for the same "real" levels of use. Most likely
D2 just allowed the size of the GC heap to grow a lot more before
triggering a collection, but we were hyper-cautious about getting
identical resource usage just on the offchance it might have been
something nastier.
> That doesn't mean D would beat Rust in a competition on who
> makes the best discord software. It really depends on a lot of
> factors, and I don't think generalizing Go and D to be the same
> because they both have a GC is fair or accurate.
For those apps that really couldn't afford a single GC cycle, we
did have some discussions about how, if we were writing from
scratch, Rust's memory model might have been a nice fit (it was
no fun having to monitor those apps for signs of GC cycles and
then work out what was causing them). It would certainly have
been _interesting_ to try to write those apps in Rust. But I
think we would have missed a lot of other things that were also
important: the friendliness of the code, the ease of iteration,
and especially the compile-time introspection and metaprogramming
that even in D1 were a major, major help.
I've had a little bit of a go at metaprogramming in Rust, and ...
I can't say I like it :-)
It's difficult not to feel that maybe what really made the
difference for Discord was not really the language, but that this
time they got the design right. But maybe, for them, Rust's
strictness was a way of settling design questions that they could
have sorted out for themselves but only by having debate and
consensus and making sure that everyone was consistent in doing
the right thing. And Rust probably took all that off the table.
More information about the Digitalmars-d
mailing list