Hacker News new | ask | show | jobs
by ramblerman 1068 days ago
You seem to be conflating speed and memory usage.

A spring boot app will generally be very performant. It will indeed use more memory though.

4 comments

I did an excercise some time ago and managed to get two file transfer apps, one in Rust and one in Java, where the performance was effectively the same (in some cases with a slight Java edge!), but the memory consumption was orders of magnitude in favor of Rust. The JVM is a wonder of engineering, and Java is indeed quite fast.
Most reasonable people in the industry understand that Java can be fast, especially in benchmark-oriented code. The problem is that the OOP-first ideology of the language and the coding culture surrounding it is not performance-oriented, especially with modern machines that don't like pointer-chasing.

One not very well known fact is that just-in-time compilers have more optimisation-specific info than pure ahead-of-time compilers, i.e. most used code paths, real types used for polymorphic values, etc. That is, until your AOT compiler uses something like a profile-guided optimisation.

In practice though writing to performance in Java takes a very dedicated effort. Real Java programs are horrible with memory, okay (for an AOT languguage) in long-running compute-intensive tasks, and painfully slow at short-living tasks such as CLI utils.

Almost any real program written in C would run circles around most off-the-shelf Java programs.

Turns out, though, all of that doesn't really matter :-)

What I noticed is that you have a lot of tools available to tune Java applications, but it was more necessary to rely on them to get to a good spot. In the Rust version, I got a 2x speed improvement by using a rayon thread pool instead of tokio, but the improvements in the Java version were 100x by the end of it.
Java tooling in general is great, that's true.

But nothing beats Vtune for squeezing the lemon of a tight loop of C code beyond any reason :-) Java just doesn't lean itself well to that kind low-level code wrangling. One misstep - and the performance house of cards falls apart.

I don’t think there is much point to these discussions without at least fixing some parameters/problem domain across languages. Of course pointer chasing is worse than a well-thought out encoding that fits many objects into a cache-line and is sequentially accessed. The question is — can the problem at hand use such a structure in the first place? Because not every problem can be solved with ECSs and the like - hell, I would even go as far to claim that most programs have a small hot loop, and otherwise spend their time slowly crawling through vast amounts of code and data in a non-orderly fashion. What part is prone to nice, sequential access is traditionally handled by the DB, which does its work very well. For the resulting 10 lines that has to be iterated through, it doesn’t really matter if it’s pointer chasing, especially when it has to wait for IO at every step in a typical server application.

So if we actually compare similar problems at hand, for a certain kind the difference is negligible, and is well offset by safety, productivity, maintainability. Hell, due to having safer primitives, one might be able to take advantage of better parallelism, that easily makes up for the slower single-core performance.

I agree with most things you say. This is why most DBs are written in C relatives or descendants: C++, Rust, or just good old C. And Java dominates in the server-side business logic domain.

But boy it's cumbersome in anything other than those long running jit-friendly server-side processes..!

PS for IO-heavy purposes almost any mem-managed language would do. The real code running there is OS figuring out hardware and physical reality.

Aren't file transfers done by the kernel via sys-calls?

All languages would be equally fast, given they don't do something stupid like reading and writing individual bytes.

They both boiled down to a sendfile call, effectively. The differences came to runtime weight, and parallelism strategy/implementation. It turns out that not having to pay for object headers/stack allocation by default, helps a lot more than I anticipated. I did this to actually measure what the difference was.
No man spring boot is hideously slow as well compared to vanilla java. It's pretty fast compared to many other things, but that's just because vanilla java is extremely fast.

You often see like 15-30 second start times for springboot apps, which is hilarious and 13-28 seconds longer than it has any business taking.

startup time?

Any java performance test is generally done against a warmed up VM - which would be representative of the 99.99% of the time the app is running. With or without spring boot.

Startup time matters too. There's no reason you should have 2003 start times in a 2023 application.

A java application should be able to start in seconds. An inability to do so is the surefire litmus test for pulling in too many dependencies.

Have you tried Spring native?
I've tried and worked with most of what the Spring ecosystem has on offer, and I'm not particularly impressed. It seems to codify all the practices that makes for mediocre software.
As a data point I ported a spring boot application to rust and max memory lowered from 200 mb to 9 mb.
I wonder how much you'd save with Micronaut: https://micronaut.io/

> Micronaut is a software framework for the Java virtual machine platform. It is designed to avoid reflection, thus reducing memory consumption and improving start times. Features which would typically be implemented at run-time are instead pre-computed at compile time.

https://en.wikipedia.org/wiki/Micronaut_(framework)

I don't think you'd go down to 9, but something like 20-30 could be doable.

Actually I ported it to Micronaut too and compiled it to native code. It's difficult to know exactly what the minimum amount of memory that a java application could run with during normal load, but I'd estimate that it was around 150 mb instead of 200 which was disappointing, 128 mb got intermittent OOMs. But the code was nicer than spring boot (or rust).
You should get your hands on say, go and go-fiber, and compare that with spring boot regarding speed and memory. And I say that with our main backend being kotlin/java and spring boot. It's a nightmare and absolute and utter garbage.
Why would it be “absolute and utter garbage”!