upvote
I decompiled Project Zomboid (written in Java) a while back, because I was curious about the performance issues I was having with the game. (Very laggy on my 10 year old laptop, while looking like The Sims 1.) I figured, best case scenario I find some easy bottlenecks and I can patch in a fix.

Well, the whole thing was standard Java OOP, except they also had a bunch of functional programming stuff on top of that. I can relate to that -- I think they were university students when they started, and I definitely had an OOP and FP phase. But then they just... kept it, 10+ years later.

So while it's true that you can write C in any language... those kind of folks don't tend to use Java in the first place ;)

--

(Except Notch? Well, his code looks like C, not sure if it's actually fast! I really enjoyed his 4 kilobyte java games back in the day, I think he published the source for each one too.)

EDIT: Found it!

https://web.archive.org/web/20120317121029/http://www.mojang...

Edit 2: This one has a download, still works!

https://web.archive.org/web/20120301015921/http://www.mojang...

reply
What is the ending of your story!? Did you find and fix some bottlenecks?
reply
Java doesn't steer you into object pools. I wrote Java code for 20 years and never used a cache to avoid allocating objects, and never saw a colleague use one. The person you were talking to doesn't know what he's doing.
reply
This point gets raised every single time managed languages and low latency development come up together. The trade off is running "fast" all of the time, even when you don't have to, vs running slow most of the time and tinkering when you need to go fast.

I've spent a fair few years developing lowish (10-20us wire to wire) latency trading systems and the majority of the code does not need to go fast. It's just wasted effort, a debugging headache, and technical debt. So the natural trade off is a bit of pain to make the hot path fast through spans, unsafe code, pre-allocated object pools, etc and in return you get to use a safe and easy programming language everywhere else.

In C# low latency dev is not even that painful, as there are a lot of tools available specifically for this purpose by the runtime.

reply
You might have an application for which speed is not important most of the time. Only one or two processes might require allocation-free code. For such a case, why would you burden all of the other code with the additional complexity? Calling out to a different language then may come with baggage you'd rather avoid.

A project might also grow into these requirements. I can easily imagine that something wasn't problematic for a long time but suddenly emerged as an issue over time. At that point you wouldn't want to migrate the whole codebase to a better language anymore.

reply
I saw something like that being suggested when working with GIS data with many points as classes in Java, the object overhead for storing XYZ doubles is quite crazy. The optimization was to build a global double array and use "pointers" to get and set the number in the array.

Even JavaScript is much better for this, much, much better.

reply
JavaScript has the exact same issue - objects are on the heap and require allocation and pointer dereferencing. For huge collections of numbers, arrays might be better.

But JS has another problem: there's no way to force a number to be unboxed (no primitive vs boxed types), so the array of doubles might very well be an array of pointers to numbers[1].

But with hidden class optimizations an object might be able to store a float directly in a field, so the array of objects will have one box per (x,y,z), while an array of "numbers" might have one box per number, so 3x as many. My guess is, without benchmarking, is that JS is much worse than Java then, because the "optimization" will end up being worse.

[1]: Most JS engines have an optimization for small ints, called SMIs, that use pointer tagging to support either an int or a references, but I don't think they typically do this optimization for floats.

reply
You're describing array of structs vs. struct of arrays. Even in JavaScript, you would have to manually do the latter.
reply
V8 automatically optimizes objects with the same shape into efficient structs, making array of objects much more efficient than in Java.

And the manually manager int array acts more like system memory, it's not continuous, so you could have point i 0 and 2 and the data would be: [1, 2, 3, x, x,x, 3, 2, 1] (3D points).

So I am not describing a struct of arrays.

reply
Hidden class optimizations just make JavaScript objects behave a little more like Java class instances, where the VM knows where to find each field, rather than having to look it up like a map.

It doesn't make JS faster than Java, it makes it almost as fast in some cases.

reply
The problem with comments like these is that guessing what "better language" a commentator has in mind is always an exercise left up to the reader. And that tends to be by design—it's great for potshots and punditry, because it means not having make a concrete commitment to anything that might similarly be confronted and torn apart in the replies—like if the "better language" alluded to is C (and it generally is)—the language where the standard library "steers" you towards quadratic string operations because the default/natural way to refer to a string's length is O(n).
reply
TBH, I do not see how Java as a language steers anyone to use one those shotguns. E.g. the knowledge about algorithmic complexity is foundational, the StringBuilder is junior-level basic knowledge.
reply
How would you handle validating numeric input in a hot path then? All of the solutions proposed in #5 are incomplete or broken, and it stems from the fact that Java's language design over-uses exceptions for error handling in places where an optional value would be much safer and faster.
reply
Normally in 100% cases, with parseInt/parseDouble etc. Getting NumberFormatException so frequently on a hot path that it impacts performance means, that you aren’t solving the parsing number problem, you are solving a guessing type problem, which is out of scope for standard library and requires custom parser.
reply
Okay, but this contradicts your original statement that "Java doesn't steer anyone to use these [footguns]". Every language has a way to parse integers, and most developers do not need a custom parser. Only in Java does that suddenly become a performance footgun.
reply
It does not. If you need to parse a number, you use standard library and you will be fine. The described case with huge impact on hot path is the demonstration why using brains is important. The developer that will get into this mess is the one who will find the way to suffocate his code with performance bottlenecks in thousand other ways. It’s not a language or library problem.
reply
Yes, parseInt et al work very fast for good inputs. What percentage of your inputs are invalid numbers and why ?
reply
> What percentage of your inputs are invalid numbers and why ?

This is a wrong question to ask in this context. The right question to ask is when actually exceptional flow becomes a performance bottleneck. Because, obviously, in a desktop or even in a server app validating single user input even 99% of wrong inputs won’t cause any trouble. It may become a problem with bulk processing, but then, and I have to repeat myself here, it is no longer a number parsing problem, it’s a problem of not understanding what your input is.

reply
deleted
reply
> So just manual memory management with extra steps

This is actually the perfect situation: you are allowed to do it carefully and manually for 1% of code on the hot path, but you don't have to worry about it for the 99% of the code that's not.

reply
Bad idea. I've made a pool allocator before, but that was for expensive network objects and expensive objects dealing with JNI.

Doing it to avoid memory pressure generally means you simply have a bad algorithm that needs to be tweaked. It's very rarely the right solution.

reply
[dead]
reply