I found claude and GPT very helpful on this, because java have a very sofisticated monitoring harness. Just ask the agent to connect to the running application (on kubernetes or whatever) on prod and do a java flight recording then analyze allocations.
I managed to improve some applications of ours from several garbage collections per second to several minutes between collections. That _really_ improves p99.
Take a peek at jolokia if you've never used it :) Attach it as a JVM agent to _any_ process to expose it's JMX attributes as http calls, and it even gives you a neat little console to log into.
If you want to collect these, telegraf has a jolokia plugin. It's an incredible combination!
Nothing much smarter than run the agent in the project folder, make sure it has means to interact with production (like configured kubectl) and ask it to jcmd the hell out of it.
I think it said something very meaningful and actionable (admittedly at a high level) about keeping the hot path deterministic: low allocations (including guidelines for GC frequency targets), don't use vthreads (instead use one thread on a pcore that never sleeps, to avoid amdahl), caution about techiques that work at p99 and fail at 99.999... This is not typical for "enterprise" Java, and is an interesting article for those who wish their systems were more deterministic (but may not be aware of the techniques or their cost). This is not a "how to", but that's fine. It's still good content.
Yes, disappointing given that Chronicle actually does have legit expertise here. (Chronicle Map is not very well-known even in the Java space but it's by far the best larger-than-memory Map available.)
Yes. & in the end my experience has been that you can write low latency code with gc, but only by expending more effort than it'd take to use manual memory management
First of all it depends on the language, what GC models it supports, and what are the performance SLAs.
Secondly if we are talking about something like real time audio, or sending the maximum amount of triangles per second, then there is zero memory management, the code should be allocation free across all the critical path, regardless of the language.
Had to write a router software once in Java back in 2014. The past experience in me believed that its not a good choice to use something with stop the world GCs for routers. The goal was to have everything under 1ms (max 2ms in rare cases). It has http server on head and websocket connections on the tail end. Turns out the class instantiations and JSON parsing were a bottleneck. Thread safe resources were valuable, the libraries which did not had thread safe resources were re-written to support what we needed. The http server was re-written barebones, the JSON parsing was re-written with barebones. And it worked.
How about not using Java? Then you can have low latency.
Average go, rust, c++ and c will outperform amazing java programs, and the former will also be way way more easy to run, troubleshoot, interpret logs from.
I need a UI which runs well on Windows, MacOS, and Linux, without having to build three different ones. Swing is still easily the best, most consistent, and most native-feeling cross-platform environment. It's much better than QT and GTK in most respects. And Java also runs elegantly on a little platform you may know as Android. I have high hopes for go and rust. But until they have mature UIs, they're out (for me).
C and C++ are dangerous languages filled with security failings and footguns, and no modern app should be written in them.
It's been my experience that well-written low-level Java code runs at about 75% the speed of good C code. (Of course lazy coders write in cushy Java which is much slower). When written efficiently, Java's biggest slowdown lies in array access (C and C++ array access is fast because it is very, very unsafe). But Java makes up for this in having a GC which will coalesce related objects into the same page and so take advantage of cache coherency effects in ways malloc and free cannot possibly do. I have some allocation-heavy algorithms in Java which are, as a result, significantly faster than well-written equivalents in C.
In heavily performance-engineered code having a GC coalesce memory is a pessimization in all cases.
I've done a lot of performance engineering in both C++ and Java. Every optimization available in Java also exists in C++ but the reverse is not true, which is why C++ is always faster. Every example I have ever seen of Java being faster than C++ was just poorly optimized code. The heuristic I use is that heavily optimized C++ is about twice as fast as heavily optimized Java at the limit. And this requires some non-idiomatic and ugly Java that isn't nice to maintain.
This doesn't necessarily make Java the wrong choice though. Few organizations prioritize absolute performance above all other things. There are practical tradeoffs.
What type and size of applications have you worked on?
@pron, who works on the JVM and is a C++ expert, has been writing a lot recently about low level languages becoming increasingly impossible to optimize with more LOC and more people working on it (dozens, or even hundreds of developers).
The idea being be a language with an aggressive JIT, moving garbage collector, and bump allocation is going to allocate/deallocte faster than malloc, and get the most important average optimizations at all times, where as the equivalent low level app will struggle to get the ideal allocation pattern the more people that work on it, or be forced to use slow dynamic dispatch. He wouldn't describe a GC as pessimistic, he'd say it's literally faster, and that's why he (a C++ programmer) works on it. The JVM was built by people saying "we are doing a handful of the same things in C++ all the time."
There are specific cases where it's good to have low level control, but they aren't everywhere.
May be true between late 90s to late mid 10s. Both Java and JVM has had enormous of work going into it. 2026 the JVM is pretty damn good pieces of engineering.
If low latency is your goal than you don't want JIT. JIT has two issues in low latency, first the first time through your code isn't compiled yet and so you get high latency. Second, it optimizes for the common case, which means when you hit an exception that exception will be higher latency because everything hits a branch miss.
Of course we are talking generals here. Sometimes the above is acceptable and Java/JIT is just fine. Sometimes it is unacceptable and you cannot use Java/JIT. Know your domain.
Of course in all cases (C, Rust, C++), you have to understand the system and what it is doing. Every language has a standard library that will do things that are not low latency on you. You have to know which library functions will do what, memory allocation and copies are both things that code often does without thought that are incompatible with low latency. No matter what you need to know what your language does that is against you.
Valid points, but this doesn't mean JIT doesn't work for relatively lower-latency coding.
To avoid the compilation etc. hit, common practice is to do some "warmups" before serving users. (Another reply has other ways to avoid this hit.)
Handling exceptions is higher latency, but they can/should be optimized out, so you're not hitting exceptions as part of your standard workflow (or even your 1% workflow).
I've done some tests with current value classes in latest prototype with full optimisation through annotation. Apparently, everything was being compiled to assembly code with no gc calls. It seems this old school ideology of slow java is about to end in near future. I'm actually intrigued how it will compete with Rust which can't optimise code further while running, while JVM JIT has more info which it could aggressively further optimise, especially hot paths.
> Average go, rust, c++ and c will outperform amazing java programs
Everyone that has a minimal experience with these knows it is not true.
While performance ceiling is likely higher in C/C++/Rust (but not Go), when we move beyond microbenchmarks Java provides competitive performance with much better ergonomics. Not to mention strictly superior tooling.
Java is a great language and runtime. Java being slow is most often a pebcak scenario. There are massive, fast, low latency, Java systems out there that have been written by competent developers.
Am I the only one who thinks "pebkac" is a self-own? If you're blaming your users for the tool, it feels like maybe your tool is just hard to use properly. I have no doubt that there are big, fast, low latency Java systems out there, but why does it take so much extra effort to build these systems in Java compared with other languages? Maybe it would be better to have competent developers focus their attention beyond managing Java's shortcomings?
I'm not even hating on Java here--I actually like the JVM quite a bit, but blaming users feels like an implicit admission.
The entire premise of the conversation is that other languages allow us to write idiomatic code and get good performance, and the parent's position was that Java requires "competent developers". So yes, the parent did say that, however...
> There's no such thing as a programming language that guarantees excellent performance regardless of programming competence.
No one made any claim remotely like this. This is a very obvious straw man argument. What was argued was that you can get decent performance from other languages without additional competence beyond idiomatic code.
> Average go, rust, c++ and c will outperform amazing java programs
Not true. Many benchmarks have shown otherwise. it is at least competitive in many areas.
> and the former will also be way way more easy to run, troubleshoot, interpret logs from
No language will save you from poor logging practices. If you log every debug log it's not Java's problem. No 1 says you have to log the full stack trace if that's your concern. You can configure / strip / do anything. Learn to use the stack.
I managed to improve some applications of ours from several garbage collections per second to several minutes between collections. That _really_ improves p99.
There's also async profiler. LLMs just use whatever. Lots of choices.
If you want to collect these, telegraf has a jolokia plugin. It's an incredible combination!
https://blog.vanillajava.blog/2026/06/testing-java-memory-ma...
https://blog.vanillajava.blog/2026/06/why-you-should-tun-cod...
Suggestions welcome, it can be hard to know what to include or not.
Secondly if we are talking about something like real time audio, or sending the maximum amount of triangles per second, then there is zero memory management, the code should be allocation free across all the critical path, regardless of the language.
I.e. all alloc should happen up front, functions should have predictable execution time, etc etc
Average go, rust, c++ and c will outperform amazing java programs, and the former will also be way way more easy to run, troubleshoot, interpret logs from.
Java is usch garbage in every stack.
C and C++ are dangerous languages filled with security failings and footguns, and no modern app should be written in them.
It's been my experience that well-written low-level Java code runs at about 75% the speed of good C code. (Of course lazy coders write in cushy Java which is much slower). When written efficiently, Java's biggest slowdown lies in array access (C and C++ array access is fast because it is very, very unsafe). But Java makes up for this in having a GC which will coalesce related objects into the same page and so take advantage of cache coherency effects in ways malloc and free cannot possibly do. I have some allocation-heavy algorithms in Java which are, as a result, significantly faster than well-written equivalents in C.
I've done a lot of performance engineering in both C++ and Java. Every optimization available in Java also exists in C++ but the reverse is not true, which is why C++ is always faster. Every example I have ever seen of Java being faster than C++ was just poorly optimized code. The heuristic I use is that heavily optimized C++ is about twice as fast as heavily optimized Java at the limit. And this requires some non-idiomatic and ugly Java that isn't nice to maintain.
This doesn't necessarily make Java the wrong choice though. Few organizations prioritize absolute performance above all other things. There are practical tradeoffs.
@pron, who works on the JVM and is a C++ expert, has been writing a lot recently about low level languages becoming increasingly impossible to optimize with more LOC and more people working on it (dozens, or even hundreds of developers).
The idea being be a language with an aggressive JIT, moving garbage collector, and bump allocation is going to allocate/deallocte faster than malloc, and get the most important average optimizations at all times, where as the equivalent low level app will struggle to get the ideal allocation pattern the more people that work on it, or be forced to use slow dynamic dispatch. He wouldn't describe a GC as pessimistic, he'd say it's literally faster, and that's why he (a C++ programmer) works on it. The JVM was built by people saying "we are doing a handful of the same things in C++ all the time."
There are specific cases where it's good to have low level control, but they aren't everywhere.
May be true between late 90s to late mid 10s. Both Java and JVM has had enormous of work going into it. 2026 the JVM is pretty damn good pieces of engineering.
C++ or go? Then you'll have to take a very closer look, because the java JIT is wonderful. A masterpiece of several hands, actually.
Of course we are talking generals here. Sometimes the above is acceptable and Java/JIT is just fine. Sometimes it is unacceptable and you cannot use Java/JIT. Know your domain.
Of course in all cases (C, Rust, C++), you have to understand the system and what it is doing. Every language has a standard library that will do things that are not low latency on you. You have to know which library functions will do what, memory allocation and copies are both things that code often does without thought that are incompatible with low latency. No matter what you need to know what your language does that is against you.
To avoid the compilation etc. hit, common practice is to do some "warmups" before serving users. (Another reply has other ways to avoid this hit.)
Handling exceptions is higher latency, but they can/should be optimized out, so you're not hitting exceptions as part of your standard workflow (or even your 1% workflow).
There's startup "AOT cache" via Leyden that speeds up startup. Isn't native speed up it's quite a big boost.
Then there's GraalVM that does give you a native image. Real AOT.
Everyone that has a minimal experience with these knows it is not true.
While performance ceiling is likely higher in C/C++/Rust (but not Go), when we move beyond microbenchmarks Java provides competitive performance with much better ergonomics. Not to mention strictly superior tooling.
Am I the only one who thinks "pebkac" is a self-own? If you're blaming your users for the tool, it feels like maybe your tool is just hard to use properly. I have no doubt that there are big, fast, low latency Java systems out there, but why does it take so much extra effort to build these systems in Java compared with other languages? Maybe it would be better to have competent developers focus their attention beyond managing Java's shortcomings?
I'm not even hating on Java here--I actually like the JVM quite a bit, but blaming users feels like an implicit admission.
There's no such thing as a programming language that guarantees excellent performance regardless of programming competence.
> why does it take so much extra effort to build these systems in Java compared with other languages?
They didn't say that.
The entire premise of the conversation is that other languages allow us to write idiomatic code and get good performance, and the parent's position was that Java requires "competent developers". So yes, the parent did say that, however...
> There's no such thing as a programming language that guarantees excellent performance regardless of programming competence.
No one made any claim remotely like this. This is a very obvious straw man argument. What was argued was that you can get decent performance from other languages without additional competence beyond idiomatic code.
Not true. Many benchmarks have shown otherwise. it is at least competitive in many areas.
> and the former will also be way way more easy to run, troubleshoot, interpret logs from
No language will save you from poor logging practices. If you log every debug log it's not Java's problem. No 1 says you have to log the full stack trace if that's your concern. You can configure / strip / do anything. Learn to use the stack.