$ echo 'class Hello { public static void main(String[] args) { System.out.println("Hello, world"); } }' >Hello.java
$ javac Hello.java
$ java --version
openjdk 21.0.7 2025-04-15 LTS
OpenJDK Runtime Environment Zulu21.42+21-CRaC-CA (build 21.0.7+6-LTS)
OpenJDK 64-Bit Server VM Zulu21.42+21-CRaC-CA (build 21.0.7+6-LTS, mixed mode, sharing)
$ time java -cp . Hello
Hello, world
real 0m0.026s
user 0m0.010s
sys 0m0.018s
For some reason this machine is still on 21. Anyway, the overhead of the JVM itself is pretty low.For small tools it's fine:
$ echo 'class Dig { public static void main(String[] args) throws Exception { var addr = java.net.InetAddress.getByName(args[0]); System.out.println(addr); } }' >Dig.java
$ javac Dig.java
$ time java -cp . Dig news.ycombinator.com
news.ycombinator.com/209.216.230.207
real 0m0.047s
user 0m0.026s
sys 0m0.021s
$ time host news.ycombinator.com
news.ycombinator.com has address 209.216.230.207
news.ycombinator.com has IPv6 address 2606:7100:1:67::26
real 0m0.052s
user 0m0.005s
sys 0m0.004s
Java startup gets slow when you use some massive framework like Spring. If you need a program to start fast, don't use one! void main() {
IO.println("Hello world");
}
$ time java Hello.java
Hello world
real 0m0.662s
user 0m2.421s
sys 0m0.198s
void main(String[] args) throws Exception {
IO.println(InetAddress.getByName(args[0]));
}
$ time java Dig.java news.ycombinator.com
news.ycombinator.com/209.216.230.207
real 0m1.154s
user 0m2.379s
sys 0m0.222s #!/usr/bin/java --source 25
void main(String[] args) throws Exception {
var addr = java.net.InetAddress.getByName(args[0]);
System.out.println(addr);
}Or you can just use a different framework like Micronaut which does none of that and uses an annotation processor at compile time instead. (Similar to Spring AOT, with fewer limitations)
- AOT compilation: https://openjdk.org/jeps/544 - ~100ms startup for ZGC: https://openjdk.org/jeps/545
Performance depends a lot on how you write the code. Inefficient Java code is often quite slow, but you can get surprisingly close to C++ speeds with Java in many cases, but that involves a lot of byzantine rules of how to write code so that it e.g. omits bounds checks. More realistically if you don't pay any attention you're probably running at like a 25-50% speed penalty.
Java has a leg up on statically compiled languages in that it does automatic PGO based on real run-time data which helps bridge the gap to a surprising degree. GC is also a lot more resistant to memory fragmentation from repeated small allocations than malloc, which can help as well, not just from its generational approach but also e.g. TLAB space.
It's a bit held back by not having decent access to SIMD intrinsics. Maybe will resolve itself when the Vector API gets finished baking eventually.
Almost all Java benchmarks are for the "steady state" after half an hour of warm up time.
Hotspot's AOT is promising and doesn't have those pitfalls, but has not yet been delivered.
There are other solutions that give you MUCH faster startup with lower memory e.g.: https://foojay.io/today/java-server-work-before-startup/
Edit: it seems I missed that 28 added the actual native code compilation phase so it will probably be closer to the GraalVM numbers in the link above.
OpenJDK, OpenJ9, Azul, PTC, Aicas, microEJ, ART (even if not Java TM), GraalVM, Bluesoft,..
Also performance for what?
As long production SLA are met, that's a deployment success.
For example, the C++ replacement for a Java program bottlenecking my CI takes 1/3rd as long (with less variance) and runs on a smaller instance.
You missed to account the hours spent writing the application in C++, related memory and UB bugs, the additional security issues plugging a language like C++ directly into the Internet.
Additionally, you also failed to account Java has JNI, which means only a few hot-spots might be rewriten into something like C++, not the whole application.
Finally, with Panama, it is possible to design a memory layout off heap, similar to what would be done with C++.
Naturally this requires some low level programming skills, the benefit is that one keeps enjoying the ecosystem.
Finally, SLAs also include execution time, of course.
So long as you are willing to do a training run, you can get pretty decent startup times.