Reusing memory used to be pretty standard for C/C++ programmers; and is also standard practice for "real time Java."
But on top of that, neither the slab allocator nor the GC are free. They're fast, and they're very good, but they also make heavy use of the memory bus, thus competing heavily with the cache-thrashing already being caused by the objects being allocated.
This is why in Java, on a heavily threaded and heavily loaded process, you can see that the CPU cores are far from 100% utilization, but yet there's no blocked threads (and more threads than cores). In other words, once the memory bus saturates, the effective throughput of the CPU drops off and the system cannot make full use of the processing power available.
The relative cost of memory access has gone up 2 orders of magnitude in the past 25 years, and that's before the bus becomes saturated. When the bus is saturated, it can go up dramatically from there (see: queue theory).
That is the problem with utilization; you have no clue how busy the CPU actually is. IPC is more useful in these situations.
That said, otherwise you're right that the JVM generally makes use of the generational hypothesis depending on the collector. The Gen 0 is referred to as Eden in Java-land and uses thread-local allocation buffers that just bump pointers to allocate. They're basically just like arena allocation.
The multi generation heap is irrelevant at that scale mentioned in the article.
Java uses something called TLABs (thread local allocation buffer) which are basically arena allocators where a new object creation is a pointer bump (no need to even synchronize!). Later the GC will move longer-lived objects to a more permanent location, reusing the whole buffer for basically free.
I thought this problem was solved decades ago? Doesn't Java have a well-tuned generational garbage collector that can handle this?
.Net was hyper-optimized for this over a decade ago with its 3-generation system, where the 0th generation allowed for extremely rapid allocation and collections. I thought Java had similar capabilities?
(Summary, which BTW is probably outdated)
0 generation: Pre-allocate a continuous chunk of RAM. Every allocation goes to the next bytes of the chunk. When there's no more free RAM left, find all reachable objects in the 0 generation and copy them to the 1 generation.
1 generation: Works the same as the 0 generation, except it's larger and objects are copied to the 2 generation.
2 generation: Garbage collections here are traditional "mark and sweep" collections.