Live data from Hacker News

Every Byte Matters

fzakaria.com

91–100 of 159 posts

Re: Every Byte Matters

#91
post #11

The JVM is currently pretty bad for memory allocation. Every object (i.e. not a primitive) has a header that IIRC is 12 bytes. But there is good news in JVM land: this will be reduced to 8 bytes in the next JVM release, and Project Valhalla will give the tools to do away with headers entirely in some cases. Project Valhalla also has tools to manage off-heap memory, which is important in many cases. The JVM is an odd…

> Every object (i.e. not a primitive) has a header that IIRC is 12 bytes. But there is good news in JVM land: this will be reduced to 8 bytes in the next JVM release Since JDK 25 it's already 64 bits with the `-XX:+UseCompactObjectHeaders` flag [1], but in JDK 27 it will be the default [2]. > where it requires too much heap to compete with the AOT compiled languages Not to compete but to beat, and not too much, but t…

What do you mean by “control”?

Re: Every Byte Matters

#92
post #33
post #9

> The cost of each new field is rarely considered Most developers, in Java and in most other languages, do not consider the cost of every field, but I can tell you that people who need micro-optimisations certainly do care, and in Java's standard library, a layout is very much a concern (except, as always, you want to optimise what really matters; there's no point in optimising something that is unlikely to be a hot…

> Most developers, in Java and in most other languages, do not consider the cost of every field Are you saying most developers are bad? It’s the equivalent of most employees don’t consider the cost of every action to the employer and is how company spend blows up.

No, it means the opposite.

Re: Every Byte Matters

#93
post #63

Earlier quoted context omitted.

I don't know what it is that Rust demonstrates given that few large scale projects have chosen it, but I've seen nothing to indicate that it doesn't suffer from the same performance issues as C++ compared to Java. The point of bringing up Rust is that it also gives the compiler much more information to optimize on than C++, but actual performance is comparable or slightly worse in most benchmarks because the quality…

> Some of those Rust advantages are exactly the same things that have been touted as major advantages for Java over C++, like escape analysis and lifetimes. These aren't the biggest advantages. I would say that the biggest ones are aggressive speculative optimisations that allow inlining of virtual calls (by default, up to a depth of 15 calls) and the ability to freely move pointers, which allows alternatives to free…

LLVM does speculative devirtualization as well these days, though it's not as aggressive as Hotspot. High-performance native code tries to avoid deep dynamic hierarchies anyway, so it's mitigated by cultural practices.

GCs are definitely a strong point for Java, but most high-performance code can be rewritten to avoid pummeling memory management. This used to be common for Java in financial applications, not sure if it still is.

C++ has evolved its own compacting GCs like oilpan [0] for applications where high performance is inherently tied to allocation. Oilpan runs into pointer issues and isn't remotely comparable to G1GC or ZGC, but I think the speed of V8 speaks for itself. Rust allows you to drop in non free-list based allocators and GCs (e.g. Bumpalo), but they're relatively immature.

    That may be because the information on that page seems to be up to date to 2011-2. Java is now on version 26, BTW.
The last time I dove into JVM internals was around the same time. I figured that someone who's worked with it more recently might have better examples than what's easily searchable.

[0] https://chromium.googlesource.com/v8/v8/+/main/include/cppgc...

Re: Every Byte Matters

#94
post #61

Earlier quoted context omitted.

A sibling comment also mentioned Jai. Not sure what I am missing that the original post was explicitly referring to Jai, some inside joke maybe? I am sorry, I only know Odin. Jai is this cult on reddit/discord, right? You get access if you socialize enough or something? Not my thing. Not for a language.

(original poster here) I was just throwing out an idea. I had no idea there were already implementations! Because, to my knowledge, conventional popular languages like C/C++/C#/Java/JS/Python don't do that, and automatically doing that (under certain conditions) feels like an easy performance win.

For what it’s worth, a common example of the capabilities of c++26 reflection is exactly this use case. I can’t remember where I first saw it, but this article [0] showcases the technique pretty well. It’s opt-in so not the compiler optimization that you’re imagining but still neat that it’s possible

[0] https://brevzin.github.io/c++/2025/05/02/soa/

Re: Every Byte Matters

#95

Earlier quoted context omitted.

> SoA is weak if you are adding/removing monsters more often than accessing a single "hot" field. Why is that? Genuinely curious. Does "weak" mean that it performs worse than AoS, or that the gains aren't as significant versus AoS?

It's because removing a monster with 20 fields from an SoA structure means resizing 20 arrays. Removing the same monster from an AoS array involves resizing a single array, which you're going to process in a very cache friendly way.

I'm not sure why anybody would at the same time be implementing SoA AND resizing 20 arrays for a single delete, those things seem to be on either ends of the "I care about performance" spectrum.

Re: Every Byte Matters

#96
post #39

Earlier quoted context omitted.

In general, the tradeoff is between optimisations that help large programs vs optimisations that help small programs. Do you have concrete examples of large scale Java programs that are significantly more performant than comparable programs in native languages like C++? My understanding was that this dynamic hadn't fundamentally changed much since the 2010s, when Java was able to occasionally edge out a win in 1-2 be…

> Do you have concrete examples of large scale Java programs that are significantly more performant than comparable programs in native languages like C++? Yes. I was working in a place that made large sensor-fusion applications, air-traffic control applications, and logistical planning, each in the 2-8MLOC range. Over time, we ported all of them from C++ to Java because C++'s performance overheads were too annoying t…

I’ve done performance-engineering for decades in Java, C++, and C for both data analytics and supercomputing/HPC. Java performs significantly worse than C++ in all cases without exception. This is the result you should expect from first principles; something has gone horribly wrong with your software optimization if Java is faster than C++ or even Rust.

There are good reasons to use Java in environments that care about performance. Absolute performance can be traded for other concerns while still being good. It is why I did so much performance-engineering work in the language.

Most performance is architectural in nature. Extremely granular control of scheduling is a prerequisite. System languages provide that control if you want it, Java does not.

When you design software in Java, you accept that some software architectures are not available to you. If you care about performance, you would not port a software architecture optimized around the limitations of Java to a systems language.

Re: Every Byte Matters

#97
post #39

Earlier quoted context omitted.

> Do you have concrete examples of large scale Java programs that are significantly more performant than comparable programs in native languages like C++? Yes. I was working in a place that made large sensor-fusion applications, air-traffic control applications, and logistical planning, each in the 2-8MLOC range. Over time, we ported all of them from C++ to Java because C++'s performance overheads were too annoying t…

”they ported a small-to-medium service from Java to Rust. The result was such a huge performance drop that it wouldn't meet their minimum requirements” That result would say less about performance of languages than it would about competency of developers with a language. I just don’t buy that a task could be assigned to two teams with comparable expertise and domain knowledge in Rust and Java, and have the Rust resul…

It may well be the case that it's not an apples-to-apples comparison, but as someone with over two decades of experience in both Java and C++, I find it not only unsurprising, but as a case of both Java and Rust doing exactly what they're designed to do.

Rust is designed to be a low-level language, i.e. a language with maximal control with all of its pros and cons (albeit with memory safety, which C++ doesn't have), while Java is designed to address the performance issues low level languages have, particularly as they get larger, due to their control constraints. Without such constraints, it is easier to offer better performance for less effort especially as programs grow.

In that particular program I was told that the differences were due to needing more locks in the Rust version. As has always been the case, they managed to achieve parity with much more effort (that is expected to continue over the lifetime of the software), but again, this is the explicit tradeoff of the approaches.

Thirty years ago, and even twenty years ago (when Rust was first being designed) many still believed that more control is the only path to good performance, even if it comes with a lot of effort. Today it's clear that it's not the only path, and the debate is mostly around which program and workload patterns that happen to work better with one approach or the other are more common.

Re: Every Byte Matters

#98
post #63

Earlier quoted context omitted.

> Some of those Rust advantages are exactly the same things that have been touted as major advantages for Java over C++, like escape analysis and lifetimes. These aren't the biggest advantages. I would say that the biggest ones are aggressive speculative optimisations that allow inlining of virtual calls (by default, up to a depth of 15 calls) and the ability to freely move pointers, which allows alternatives to free…

LLVM does speculative devirtualization as well these days, though it's not as aggressive as Hotspot. High-performance native code tries to avoid deep dynamic hierarchies anyway, so it's mitigated by cultural practices. GCs are definitely a strong point for Java, but most high-performance code can be rewritten to avoid pummeling memory management. This used to be common for Java in financial applications, not sure if…

> LLVM does speculative devirtualization as well these days, though it's not as aggressive as Hotspot. High-performance native code tries to avoid deep dynamic hierarchies anyway, so it's mitigated by cultural practices.

Sure, AOT compilation also didn't stand still, and overall I'd say that Java and low level languages are closer today than they were 20 or even 10 years ago on all fronts: both have improved in areas where they were behind.

> This used to be common for Java in financial applications, not sure if it still is.

Given that low-latency collectors are only 3 years old, I'm sure some existing Java applications still do it, but new ones no longer need to (and it may turn out to be counterproductive with the new collectors)

> Rust allows you to drop in non free-list based allocators and GCs (e.g. Bumpalo), but they're relatively immature.

The problem isn't the immaturity but the integration with the standard library that requires significant code changes (e.g. you need to use different string and collection implementations). However, even where there is good integration - as in the case of Zig - arenas impose limitations (due to the care that needs to be given to lifetime) that make the program less flexible. But yes, when all the stars are aligned, arenas can beat moving collectors (that's about the only thing that can), but moving collectors aren't standing still and resting on their laurels, either.

> I figured that someone who's worked with it more recently might have better examples than what's easily searchable.

I don't know about a single unified resource, but you can find everything here: https://openjdk.org/jeps/0

JIT improvements are usually too low-level to merit a JEP, but all the major GC changes are there. For a taste of what's going on in the JIT these days, see this recent talk: https://youtu.be/J4O5h3xpIY8

Re: Every Byte Matters

#99
post #78
post #31

Earlier quoted context omitted.

Even more so, it shows that SoA data structure means you can add fields to your 1M monsters with little impact.

This is valid for sequential scanning of the data. The CPU will fill whole cache lines at once with the arrays that do get used and the algorithm touches all the field instances in the array. Now think about random access to single struct instances instead: the CPU loads a cache line worth of data for each field and uses only one element out of the whole cache line. This is much worse than a compact structure represe…

This sounds similar to relational databases vs document oriented databases, at least when I briefly looked into database like MongoDB when such things were all the rage 15-20 years ago.

For the internal web site that customer support people used a document oriented database would be great because that wants to load everything about one customer and pretty much doesn't need anything else until the user is done supporting that customer.

For the dozens or periodic reports that needed to be generated relational was way better. A given report generally only wanted a small amount of per customer data but wanted that for all customers.

A little bit of searching and LLM querying suggests that nowadays there are databases that are good at both kind of tasks, in particular Postgress with JSONB, at least at the scale we were looking at (maybe 30k or so customers), but maybe really big operations would need more specialized software.

Re: Every Byte Matters

#100
post #39

Earlier quoted context omitted.

> Do you have concrete examples of large scale Java programs that are significantly more performant than comparable programs in native languages like C++? Yes. I was working in a place that made large sensor-fusion applications, air-traffic control applications, and logistical planning, each in the 2-8MLOC range. Over time, we ported all of them from C++ to Java because C++'s performance overheads were too annoying t…

I’ve done performance-engineering for decades in Java, C++, and C for both data analytics and supercomputing/HPC. Java performs significantly worse than C++ in all cases without exception. This is the result you should expect from first principles; something has gone horribly wrong with your software optimization if Java is faster than C++ or even Rust. There are good reasons to use Java in environments that care abo…

> I’ve done performance-engineering for decades in Java, C++, and C for both data analytics and supercomputing/HPC. Java performs significantly worse than C++ in all cases without exception.

I've done similar work (not supercomputing/HPC, but yes for soft and hard realtime software, including safety-critical software) and I couldn't disagree more. Of course, we didn't get to write every program in both Java and C++, but the main question was how much effort it took to achieve the required performance. Over multiple projects it was clear that hitting the performance targets was, on the whole, significantly easier in Java.

> This is the result you should expect from first principles; something has gone horribly wrong with your software optimization if Java is faster than C++ or even Rust.

Strong disagreement here, but we need to be specific about what we mean when we say performance.

It is undoubtedly true that for every Java program there exists a C++ program with the same performance, and the proof is simple: every Java program is a C++ program with the classes being input. But that C++ program is close to 2MLOC long. The same could also be said about a C++ program vs. an Assembly program, as every C++ program could be written as an Assembly program.

But when I talk about performance, I refer to what I think most programmers care about when it comes to performance. Not how fast can a program hypothetically be given enough effort and expertise, but how fast can my program be in my budget.

Both speculative compiler optimisations and memory management optimisations are simply not an option for low level languages due to their constraints, and they are very powerful global optimisations. Given a lot of expertise and effort (that must continue throughout the software's lifetime, and often increases as it evolves) you can work around these limitations, but Java was designed so that you can benefit from them, which means more performance per unit of effort.

In large programs more general constructs (e.g. dynamic dispatch) and patterns (concurrency, great variance in object lifetime) grow in prevalence, and low level languages require more effort and discipline to work around their shortcomings in these areas. Optimising JITs that allow aggressive speculative optimisations and moving collectors were invented and adopted to address these shortcomings. You could claim that the advanced mechanisms that were developed to address C++'s performance issues have failed to achieve their goal, although it won't be easy and much of it comes down to empirical questions of which patterns arise more or less frequently in software, but given that this is what these mechanisms were at least intended to achieve, you certainly can't claim that they fail to do so "from first principles". Some compilation optimisations need speculation; some memory management optimisations need moving pointers. Not having these optimisations available in a program you can write without a lot of special effort cannot make it faster "from first principles".

So no, I don't believe at all that something has to go wrong for a Java program to be faster than a C++ program given a certain budget for the program. Indeed, in larger, more complex programs, I believe the very opposite is true. In most situations, if you get the same performance in C++ as you do in Java, then something has gone terribly wrong with your Java program.

As someone who's worked on a pretty famous JVM feature (virtual threads), I can tell you that we and the designers of low-level languages consciously make different performance tradeoffs because we optimise for different programs and people, and have different preferences when it comes to average case vs. worst case, but there is no universal dominance in performance to either one of these approaches over the other.

One obvious example was our decision to remove Unsafe from Java. Some Java developers voiced opposition, citing a program speed competition (the "one-billion-row challenge" [1]) where Unsafe improved the performance of an entry (which was later cloned and tweaked by others) by 25%. But we saw it as further motivation for the decision. Among over a dozen performance experts who submitted entries, only one was able to write a program efficient enough for Unsafe to make a big difference, and the variance in the results even among the top 20 or so entries was larger than Unsafe's improvement. By removing Unsafe, we would harm that one expert's program, but it would allow us to perform more aggressive constant-folding optimisations that would result in much greater performance improvements over the entire ecosystem. Even from a design philosophy perspective alone, this removal of control to the detriment of some programs "for the greater good" of performance over the entire ecosystem is almost unthinkable in low level languages, because control is what they're for. Did that decision make Java a faster or a slower language? That depends on how you look at performance.

[1]: https://github.com/gunnarmorling/1brc

Post reply on HN