Really Small Java Apps
august.nagro.us
august.nagro.us
A Clojure tool that parses, traverses and processes JSON (caro, see below) worked out to 3.2MB. I'm sure C and Rust can do better, but it's not bad compared to a JVM, and it's an order of magnitude better than the best option in the article. It's also small enough that while comparisons like "that's three floppies!" are interesting historical perspective, you can't reasonably complain about having a 3 MB binary in ~/.local/bin.
Examples:
https://github.com/latacora/wernicke/releases https://github.com/latacora/recidiffist-cli/releases https://github.com/latacora/caro/releases
It mostly works out of the box. My biggest frustration is that you can't easily link in dynamic libraries, which makes it a little annoying to do e.g. EC TLS with a single binary. (Go would have a similar problem but sidestepped it by reimplementing most of it natively.) Second biggest frustration: it is not a fast compiler. You're definitely doing development on the JVM (I use Graal as my default JVM now) and a "production build" afterwards with native-image.
How do they compare to go in terms of speed? Another comment also said graal native images still suffer with throughput vs using the jvm due to profile guided optimizations.
The real issue is the GC is not as efficient.
For a simple project requiring java.net.http, using these steps produced a 23MB jlink image
23MB may seem tiny today, but depending on what that "simple project" does, in absolute terms it's still twenty-three million bytes. For comparison, a full installation of Windows 3.11 is roughly that size too, not compressed. As the saying goes, "there's still plenty of room at the bottom."
It didn't really support much of anything until you started adding lots of other DLL's and libraries
Today, we get that kind of optimization, for the whole program, simply by adding -O2 to our build options, and waiting slightly longer for the compiler to complete.
Engineers using that quote are an important reason for the failure of software projects. Not only should we make efficient use of resources, but performance of software must be taken into account right from the beginning of any software project. Performance requirements must be clear from the start (how many concurrent users, how many requests per second, etc., times 2 (or 20) for safety) and when a design is made, performance requirements for each individual component should be set (and measured after implementation).
Fine tuning code is one thing, but installing a bloated package for one tiny feature should be well-considered at the time of implementation because every addition adds to the tech debt bill.
Not to mention, programs are so much more stable nowadays; I can't remember the last time my computer just locked up for no apparent reason, and I am typically pretty happy that most programs don't leak memory all over the place anymore.
Are a lot of programs bloated now? Sure, but I think I'd rather have that than having my program crash all the time because someone who didn't really know what they're doing cleared a pointer incorrectly.
I know languages like Rust and Swift have ways of safely dealing with memory without a GC, and I know Go has a non-blocking GC now, but remember that all of these things are relatively recent.
Those are very different things, to my knowledge. Rust is "no-GC" in the vein of C and C++ (but the borrow checker makes the memory management portion easier to deal in that you generally don't have to manually free stuff). Swift is "memory managed" in that is uses reference counts to automatically check through the used variables and free ones that are no longer references. In my eyes, that's pretty clearly a type of garbage collection, even if it seems the term has become specific enough that it's less often applied to that case.
That said, technically you are correct, it is a GC, just one with a lot lower overhead than something like Java/C#/JavaScript/Python.
...unless it's this sort of fun, perhaps? https://xkcd.com/303/
I strangely hear that quite often too on morning traffic ;). When will theses real professional engineers will learn?!?!?!
> make the most efficient use of resources
Can you define this? Everything can be done more efficiently.
A real professional engineers won't do premature optimization. You won't see bridges using some amazing new carbon material, it's not only too costly for the budget, it's also not needed (the bridge does everything it has to do per the requirement).
A real professional engineers will do the most he can with the resource he has, which is pretty much what we do in software engineering.
Over the years I have wasted a lot of time reviewing or discussing "optimizations" that didn't help - or even hurt - performance. Micro-optimizing some once-off init function instead of tackling major per-frame overhead and stuttering. Creating a nice lean core site and then burdening it with a billion third party scripts requested by marketing.
30MB matters for a website, or keyboard firmware.
On the other hand, my gamedev workloads often crash on 32GB machines. I measure useful SSD sizes in TB. In that context, 30MB is line noise. A rounding error. You could spend a lifetime optimizing more important performance issues, and still never turn your attention to that 30MB as something useful to spend time reducing further.
The fact of the matter is that quality simply does not matter in today's world. Not in software, not in hardware, not in food, clothing, cars, or basically any other area. It's all about minimizing costs.
Try to make software good enough to sell, and that is quickly the obvious conclusion.
Nothing about the original quote was related to Turing's law.
One interestin aspect of this is that we're going a bit back to Lisp/Smalltalk images in the mainstream, bundling runtime and code. (With few of the former's benefits, of course.) Has been done with scriptings apps, of course (Python, Perl, Tcl's Starkits), but with Java and Electron it's bound to have a wider audience.
Maybe because we can't complain about size/complexity issues anymore, now that something even more complex is common (code+runtime+wholefrigginoperatingsystem).
Our zipped distribution is 50mb. Uncompressed the executable is 26mb and the runtime is 75mb.
I'd love for it to be smaller but I can't complain. This also makes solving for Linux, macOS, and Windows pretty trivial. They each get their own zip with packaged runtime.
When did this become the new best-practice in Java land?
Note this was not possible in the past as the java license prohibited redistribution.
The recommendation now is for app developers to include their own JRE with the app; just like how each electron app includes its own copy of chromium.
Now not only is it becoming "best practice" to bundle your whole runtime with your app, people are bundling the whole operating system via Docker.
I'm curious if people have compared actually using a single JVM that is kept hot in OS cache vs separate minimal packaging for every app. It might favor single packaging if you only run 1 java app, but if you ran 10 different ones the benefits of shared code might win.
Bear in mind, a lot of what Spring -- Spring Boot in particular -- gets charged with is beyond its control. It's an entrypoint to the vast Java ecosystem, much of which is also incompatible with Graal native images at the moment.
[0] https://github.com/spring-projects-experimental/spring-fu
[1] https://github.com/spring-projects-experimental/spring-graal...
In terms of deployment of Java apps, we've found that Nomad works really well as it doesn't need a full Docker image (or equivalent) like Docker, Kubernetes etc. In Nomad you just make sure the worker node has the JDK, and then you specify the .jar file in the job.
EDIT: checking out Nomad now, since we have used other Hashicorp prods in the past...
FROM openjdk:jdk AS build
COPY . .
RUN mvn package
FROM openjdk:jre
COPY --from=build ./somepath/app.jar .
CMD java app.jar
The first stage (defined by the first FROM) is only used to build the ".jar", the second stage will only contain the JRE and the ".jar" copied from the first stage.The problem is most 3rd party libraries aren't ready for the modules switchover, so for anyone using those libraries, you are stuck with having either a 3-400mb docker image or using jlink
Not being pedantic, honestly - do you mean the JDK (which includes the compiler) or the JRE (just the VM)?