I agree. That's why you don't usually want extreme low-latency collectors that make your program slow by sacrificing throughput over latency.
> Running batch testing is exactly the kind of scenario where profiling and optimization can score big wins -- and most often, those wins also apply to the production version.
And that's why you should have a GC that balances throughput and latency.
Of course you know there's a difference between a slow program and a sluggish/unresponsive one. A user will forgive the former, but will abhor the latter. As a programmer, you're a kind of user. However, I note that many programmers have a kind of un-self-awareness when it comes to their own creations and favored, highly customized tools. If a programmer thinks something is nifty for another reason, they will often excuse much more latency than an ordinary user ever would. This is one of the biggest UX blind spots programmers have, generally.
Also, with an environment where it's easy to fix throughput, why not mostly eliminate latency? Fixing throughput is usually more straightforward and easier than fixing latency. (Pareto principle)
And that's why you should have a GC that balances throughput and latency.
In practice, due to programmer hubris and bias against perceiving flaws in our own creations, one has often ended up with GC that has better than needed throughput numbers to alleviate speed criticisms while having latency that is a little bit uncomfortable. I think it's a common programmer blindness with regards to UX.
No, because improving throughput requires a generational GC, which is something you need to design from the beginning. Once you do, it tends to be a massive win.
> In practice, due to programmer hubris and bias against perceiving flaws in our own creations, one has often ended up with GC that has better than needed throughput numbers to alleviate speed criticisms while having latency that is a little bit uncomfortable. I think it's a common programmer blindness with regards to UX.
Or maybe you don't notice any throughput problems because most mature GCs have good throughput, leading to the incorrect conclusion that throughput is unimportant. I highly suspect that if all apps were using extreme low-latency GCs, you would notice throughput problems.
Take JS, for instance: you know how JS-heavy apps are criticized all the time on HN for being slow to load? That's a throughput problem.
Not necessarily true. Often, the throughput issues can be improved by reducing memory pressure. (Though this may not cut it for situations with very high performance requirements.)
requires a generational GC, which is something you need to design from the beginning. Once you do, it tends to be a massive win.
Depending on the environment, you can switch to a higher throughput GC in production.
Or maybe you don't notice any throughput problems because most mature GCs have good throughput, leading to the incorrect conclusion that throughput is unimportant.
Maybe. Most of my experience working in GC environments was in VisualWorks, which had an excellent generational GC in its day. One of the points of pride with the VM was that it was common to see only around 2ms latency for GC pauses. There was quite a bit of work done to eliminate perceptible GC pause. For the initial experience, people would notice the GC pauses first.
In any case the words "extreme low latency GC" are yours, not mine, and I suspect you have a very particular subset in mind when you use that term, which perhaps isn't what I have in mind. Emphasis should be on low latency, to the point where the average programmer doesn't have to think about it very often, until it's time to optimize the program in general.
Take JS, for instance: you know how JS-heavy apps are criticized all the time on HN for being slow to load? That's a throughput problem.
I suspect you have a very good blog post about the details.
> No, because improving throughput requires a generational GC
Or more boxes. From the perspective of an end user or IT admin, if you have a throughput problem, you can (assuming the task lends itself) solve it with horizontal scaling. If you have a latency problem, you can only scale vertically. If scaling vertically doesn't do the trick, you're out of luck.
This is why when I have to make a choice between latency and throughput, if there's no obviously correct answer I default to latency. Intel will eventually solve my throughput problems, but they won't be able to do much about my latency problems.
But low-latency collectors have more pauses than low-throughput collectors, as well as spending more overall time collecting than low-throughput collectors. They also have a tendency towards higher memory pressure in the long run (though it's far less spiky than low-throughput collectors).
But if you never notice any of the pauses because you're very well optimized for latency, then no harm, no foul.
as well as spending more overall time collecting than low-throughput collectors.
But too-low throughput is usually only a problem in production, whereas too-high latency can increase cost (in harder to quantify ways) everywhere, including in development. Too-low throughput is also usually much easier to fix.
If you need high throughput, you need high throughput, but for most programmers, the correct default is low latency. High throughput for most programmers is like 150 mph top speed on a US sports car. In most cases, people are never going to need it, but if you need it (like, if you actually go to a track) it's relatively straightforward to implement. Whereas having unresponsive programs is like having an unreliable car that has squeaky brakes -- you're going to notice that relatively quickly, it's going to be a constant bother, and it's not so straightforward to correct.
Which model is better ? I don't know but all the car I know are the second kind. What about GCs ? I don't know, but the majority of modern GC are the second kind …
If you had a bus like this, combined with autonomous self-driving, it might revolutionize travel in the US!
Of course you usually don't need that much speed and you'll end up having a lot of pauses on your SF to NYC trip, but you'll get there a lot quicker because you'll be able to drive at 70 mph all the time.
And when you arrive, all of the driving and stopping will leave you fatigued. The steady-state travel enabled by the robot nuclear super-bus would let people travel in sleeper compartments!
Which model is better ?
Clearly the 2nd!
I don't know but all the car I know are the second kind. What about GCs ? I don't know, but the majority of modern GC are the second kind …
You seem to be leaning rather heavily on the adjective "modern." Because if you use the colloquial definition of the term, there are a number of currently maintained and used GC that aren't the 2nd kind.
For the majority of applications, those GCs are inferior to generational GCs that balance throughput and latency.
This stuff was all heavily studied in the 90s and earlier, you know. The conclusions that researchers and engineers came to are equally valid today.
D is not popular enough so far, so there will not be much research invested into its GC. When Java gets value types, it might become interesting.
Outside this sub-field, another one that offers evidence of your opinion is static analysis vs dynamic checks. Full, memory safety for C programs originally required crazy overhead (300+% sometimes) with checks on all the things that could happen. Then, people started mixing static analysis with dynamic checks and clever architectures to reduce that overhead. They'd often use static analysis to determine when they could eliminate checks. I can see something similar happening with GC's where an analysis helps avoid bad operations. We already have a taste of it with Rust where we get some safety without GC.
For some reason people keep wanting to deny the generational hypothesis, in the hopes of not having to implement a generational GC. Frankly, this is wishful thinking. The generational hypothesis has been borne out again and again and again, in all kinds of different scenarios.
Having sluggish, unresponsive, wonky tools, and a sluggish, unresponsive, wonky prototype just sucks. All of those little uncomfortable pauses wear you down and nickel-and-dime you to death.
I would think the opposite would be true, as running batch testing jobs usually demands good throughput.
Running batch testing is exactly the kind of scenario where profiling and optimization can score big wins -- and most often, those wins also apply to the production version. IMO, making your development environment uncomfortable for edit/test/debug just so you can have faster batch testing is a misguided reversal of priorities! Not having the latter provides you with less timely information, but is easily fixed. Not having the former is constantly fatiguing!