I used to write a lot of performance-optimized server code in Java. Even with heroic effort, it is difficult to make the JVM perform even half as fast as not-that-optimized C or C++ -- other languages I wrote the same kinds of code in. And highly optimized C++ is many times higher throughput than the JVM equivalent on the same hardware, pretty much always. The reasons why are well-understood technically.
This cannot be blamed entirely on the GC. The JVM makes many other choices which make optimization difficult, and its original theories about what is important for optimization haven't stood up over time. It was not designed to be performant, just good enough for most applications that are not that performance sensitive. Programming languages often have many objectives and priorities aside performance. I use Python quite a lot and it is usually much slower than the JVM.
When you say "used" how long ago are you talking about and for what types of loads?
I saw Java rewrites running circles around C++ code it replaced. It's a matter of tuning and picking the right configurations/tasks. Some things Java does really well, others it sucks at. If you need near memory access and have constant loops over arrays of objects then Java will be slower than that when compared to C++ because of the memory layout (Valhalla will improve that).
Network throughput is another weak point which amazingly NodeJS does better. Loom resolves that problem.
There's also a lot of choices when it comes to GCs nowadays. Java used to be a dog on large memory heaps. This is no longer the case with Z, G1 etc. but it's very possible you hit a problematic spot.
One of the nice things about GC performance is that you can connect a monitoring tool to a production server and optimize memory performance by viewing actual usage. Monitoring and observability in Java is at another level entirely.
> If you need near memory access and have constant loops over arrays of objects then Java will be slower than that when compared to C++ because of the memory layout (Valhalla will improve that).
In a former life we used Scala magic to pretend we had an array of structs. Otherwise, yeah, this is a huge issue facing JVM apps.
Valhalla will solve this. I disagree that this is a huge issue. There are some edge cases where this is significant but for most web/enterprise applications I don't think this is huge.
This cannot be blamed entirely on the GC. The JVM makes many other choices which make optimization difficult, and its original theories about what is important for optimization haven't stood up over time. It was not designed to be performant, just good enough for most applications that are not that performance sensitive. Programming languages often have many objectives and priorities aside performance. I use Python quite a lot and it is usually much slower than the JVM.