In projects where you can’t get away from object allocation (due to it being less deterministic for example) with some clever trick like arenas and the like, chances are the GC will be actually much faster than malloc-ing them all — and while it may not sit well with you, GC running in the background just amortizes the cost of each deallocation to basically zero time overhead (of course at the cost of memory overhead).
But I’m not trying to dismiss your experience or anything, the JVM has its place and of course there are plenty of use cases where it is not the best fit at all.
And that statement was not about the allocation time. But my understanding is that deallocation (GC) is not amortizable to constant for long-lived objects.
We can probably agree that having to code a separate class (with object overhead) to represent each little tuple of 2 integers or so, is bulky - programming-wise but also concerning the memory overhead (and possibly GC overhead).
Programming in C does not imply using malloc() to allocate individual objects. This is a bad practice.
It much depends on the task of course. My biggest project in Java was a SAT solver years ago, and millions of little clauses did not sit well with it at all. I ended up changing the data organization internally. My first attempt, the natural AOS would have been also the best choice performance-wise in C, but in Java it choked the GC. I had to switch it around to SOA which was quite awkward but it reduced the number of objects from millions to a small constant.
Also thinking of the number of lines of code running for JIT, GC, whatever... in the background all the time...