4 ms·
> Systems/infrastructure code on the other hand is subject to very different economics. It runs all the time. The ratio of development time to runtime is incred
by titzer 5y ago
> Systems/infrastructure code on the other hand is subject to very different economics. It runs all the time. The ratio of development time to runtime is incredibly small. We should optimise the heck out of infrastructure code to drive down resource usage whenever possible.
I will assume by "infrastructure code" you mean things like kernels and network stacks.
Unfortunately there are several intertwined issues here.
First, we pay in completely different ways for writing this software in manually-managed languages. Security vulnerabilities. Bugs. Development time. Slow evolution. I don't agree with the tradeoffs we have made. This software is important and needs to be memory-safe. Maybe Rust will deliver, who knows. But we currently have a lot of latent memory management bugs here that have consistently clocked in 2/3 to 3/4 of critical CVEs over several decades. That's a real problem. We aren't getting this right.
Second, infrastructure code does not consume a lot of memory. Infrastructure code mostly manages memory and buffers. The actual heap footprint of the Linux kernel is pretty small; it mostly indexes and manages memory, buffers, devices, packets, etc. That is where optimization should go; manage the most resources with the lowest overhead just in terms of data structures.
> GC has significant memory and CPU overhead. I don't want to spend double digit resource percentages on GC for software that could be written differently without being uneconomical.
Let's posit 20% CPU for all the things that a GC does. And let's posit 2X for enough heap room to keep the GC running concurrently well enough that it doesn't incur a lot of mutator pauses.
If all that infrastructure is taking 10% of CPU and 10% of memory, we are talking adding 2% CPU and 10% memory.
ABSOLUTE BARGAIN in my book!
The funny thing is, that people made these same arguments back in the heyday of Moore's law when we were getting 2X CPU performance ever 18 months. 2% CPU back then was a matter of weeks of Moore's law. Now? Maybe a couple of months. We consistently choose to spend the performance dividends of hardware performance improvements on...more performance? And nothing on safety or programmability? I seriously think we chose poorly here due to some significant confusion in priorities and real costs.
- fauigerzigerk 5y ago>I will assume by "infrastructure code" you mean things like kernels and network stacks. That, and things like database systems, libraries that are used in a lot of other software or language runtimes for higher level languages. >The actual heap footprint of the Linux kernel is pretty small And what would that footprint be if the kernel was written in Java or Go? What would the performance of all those device drivers be? You can of course write memory efficient code in GC languages by manually managing a bunch of buffers. But I have seen and written quite a bit of that sort of code. It's horribly unsafe and horribly unproductive to write. It's far worse than any C++ code I have ever seen. It's the only choice left when you have boxed yourself into a corner with a language that is unsuitable for the task. >First, we pay in completely different ways for writing this software in manually-managed languages. Security vulnerabilities. Bugs. Development time This is not a bad argument, but I think there has always been a very wide range of safety features in non-GC languages. C was never the only language choice. We had the Pascal family of languages. We had ADA. We got "modern" C++, and now we have Rust. If safety was ever good enough reason to use GC languages for systems/infrastructure, that time is now over.
- throwaway894345 5y ago> You can of course write memory efficient code in GC languages by manually managing a bunch of buffers. But I have seen and written quite a bit of that sort of code. It's horribly unsafe and horribly unproductive to write. Go uses buffers pretty idiomatically and they don't seem unsafe or unproductive. Maybe I'm not following your meaning? > If safety was ever good enough reason to use GC languages for systems/infrastructure, that time is now over. I don't know that I want GC for OS kernels and device drivers and so on, but typically people arguing against GC are assuming lots of garbage and long pause times; however, Go demonstrates that we can have low-latency GC and relatively easy control over how much garbage we generate and where that garbage is generated. It's also not hard to conceive of a language inspired by Go that is more aggressively optimized (for example, fully monomorphized generics, per this article or with a more sophisticated garbage collector). I think the more compelling reason to avoid a GC for kernel level code is that it implies that the lowest level code depends on a fairly complex piece of software, and that feels wrong (but that's also a weak criticism and I could probably be convinced otherwise).
- titzer 5y ago> It's also not hard to conceive of a language inspired by Go that is more aggressively optimized (for example, fully monomorphized generics, per this article or with a more sophisticated garbage collector). Standard ML as implemented by MLton uses full monomorphization and a host of advanced functional optimizations. That code can be blazingly fast. MLton does take a long time to compile, though. I've been working on a systems language that is GC'd and also does full monomorphization--Virgil. I am fairly miserly with memory allocations in my style and the compiler manages to compile itself (50KLOC) at full optimization in 300ms and ~200MB of memory, not performing a single GC. My GC is really dumb and does a Cheney-style semispace copy, so it has horrible pauses. Even so, GC is invisible so the algorithm could be swapped out at any time. For an OS kernel, I think a GC would have to be pretty sophisticated (concurrent, highly-parallel, on-the-fly), but I think this is a problem I would love to be working on, rather than debugging the 19000th use-after-free bug. Go's GC is very sophisticated, with very low pause times. It trades memory for those low pause times and can suffer from fragmentation because it doesn't compact memory. Concurrent copying is still a hard problem. Again, a problem I'd rather we had than the world melting down because we chose performance rather than security.
- scoutt 5y ago> This software is important and needs to be memory-safe. Let's say the GC is a binary... where is this binary? Probably somewhere in the filesystem? So now you need a filesystem written in a language that doesn't depend on the GC, just like the binary loader, scheduler, bootloader, which by the way, can boot from remote, so now you also need a network stack that doesn't use GC. You might need to show something on the screen before the GC starts up, so you will need video drivers, bus drivers, etc. written in a language that doesn't use a GC. And in which language is the GC written? You get the idea.