Earlier quoted context omitted.
Lots of tiny memory allocations are inefficient no matter what. Slight deallocation refinements to poorly made software (the reference counting part is not 'hugely inefficient') is focusing on the wrong thing.
Lots of tiny memory allocations is pretty efficient in java. The VM would have already allocated memory from the kernel so there's no context switch, and once the tiny objects are no longer referenced, deallocation is a free (0 machine instructions) side effect of garbage collection. Garbage collection isn't free, but it can be cheap(er) than reference counting millions of objects with explicit and individual allocat…
First, java ends up doing a huge number of heap allocations that are just stack allocations for other system languages.
Second, java might have some heap allocation optimization, but it's still a huge performance sink to allocate in a tight loop.
Third, reference counting is not slow. Incrementing or decrementing an integer only when a variable isn't moved can be both cheap and rare. Even better, it is deterministic. Garbage collection gets its optimization from doing bulk operations, which is exactly what becomes a problem. Any speed up pales in comparison to the speed advantage of avoiding those allocations all together. Once allocations are not weighing down performance, the lack of pauses and deterministic behavior of reference counting is an even larger advantage.
You can say that memory 'has already been allocated from the kernel' but that is what heap allocators do in any language. Jemalloc maps virtual memory and puts it into pools for sizes and threads.
At the end of the day, taking out excessive allocations is usually a trivial optimization to make. It is usually trivial to avoid in the first place. Languages fighting their garbage collector and promising the next version will have one that is faster and/or lower latency is a cycle that has been going on before java was first released. At a certain point I think people should accept that stack allocations and moves of heap allocations take care of the vast majority of scenarios and actual reference counting in this context is not a problem. Variable with unknown lifetimes should only be needed when communicating with unknown components. Garbage collection on the other hand has been a constant problem as soon as there is any neccesity for interactivity.