Live data from Hacker News

Using jlink to cross-compile minimal JREs

jakewharton.com

41–50 of 66 posts

Re: Using jlink to cross-compile minimal JREs

#41
post #6
post #5

Earlier quoted context omitted.

But I think the parent's point is given reflection, how can jlink statically know the complete set of classes that your program needs?

It's only tree shaking the JRE itself, not your whole program (unfortunately..). So as I understand it, it means no dynamically calling arbitrary classes in the JRE, but that's a much narrower limitation. Final binary size is naturally vastly reduced b/c you won't have the whole JRE, but last I tested you still end up with very chunky executables (minimal JFX GUIs were coming out to 100-200 MB)

100-200mb is a bit too large for a minimal JFX app, though it may depend on how you define minimal:

    conveyor generate javafx com.example.jfx-test && cd jfx-test
    ./gradlew jar
    conveyor make windows-app
    du -h output
71mb on disk. 31mb package size. That's a bit bigger than strictly necessary. It includes FXML and see the discussion of optional plugin modules elsewhere.

However you can easily get to 150-200mb on disk by using javafx.web because that includes a custom build of WebKit which is ~75mb all by itself.

Re: Using jlink to cross-compile minimal JREs

#42

This is awesome to know, I'm using Dart these days(java like language) that has a much smaller runtime(helloworld is 6MB), any one tried it with swing for GUI and see how large the final size is about.

Minimal Swing app is about 27mb compressed, 28mb with FlatLaf. That's for Windows. A bit smaller if you drop ECC and accessibility support.

That 6mb is just for Dart right? I thought a minimal Flutter app is about the same size as a minimal Swing app.

Re: Using jlink to cross-compile minimal JREs

#43
post #6

Earlier quoted context omitted.

It's only tree shaking the JRE itself, not your whole program (unfortunately..). So as I understand it, it means no dynamically calling arbitrary classes in the JRE, but that's a much narrower limitation. Final binary size is naturally vastly reduced b/c you won't have the whole JRE, but last I tested you still end up with very chunky executables (minimal JFX GUIs were coming out to 100-200 MB)

100-200mb is a bit too large for a minimal JFX app, though it may depend on how you define minimal: conveyor generate javafx com.example.jfx-test && cd jfx-test ./gradlew jar conveyor make windows-app du -h output 71mb on disk. 31mb package size. That's a bit bigger than strictly necessary. It includes FXML and see the discussion of optional plugin modules elsewhere. However you can easily get to 150-200mb on disk by…

Yeah, removing javafx-media and javafx-web saves a ton. It's good to point that out. It's been a couple of years, so I'll need to revisit this again later and try again

> It includes FXML and see the discussion of optional plugin modules elsewhere.

Where is this?

And do you know if it's still not possible to generate an .exe? I remember that while I was turned off by the final files sizes, what really made me drop jlink was that the final built target would always be some baroque installer (which makes sense for large GUIs that need to maintain state between runs). But you couldn't just generate a double-clickeable .exe or .appimage file that'd be equivalent to running your uberjar. So I stuck to the uberjar.. (now user have problem installing weird Java 11 Runtimes from not-Oracle)

(Further confusing things was that there is some intermediary build target in jlink also called `appimage` that's not actually an appimage, but it's quite similar..)

Re: Using jlink to cross-compile minimal JREs

#44

This is awesome to know, I'm using Dart these days(java like language) that has a much smaller runtime(helloworld is 6MB), any one tried it with swing for GUI and see how large the final size is about.

Minimal Swing app is about 27mb compressed, 28mb with FlatLaf. That's for Windows. A bit smaller if you drop ECC and accessibility support. That 6mb is just for Dart right? I thought a minimal Flutter app is about the same size as a minimal Swing app.

thanks,yes it is dart only size,need measure flutter size vs swing as a single exe

Re: Using jlink to cross-compile minimal JREs

#45
post #43

Earlier quoted context omitted.

100-200mb is a bit too large for a minimal JFX app, though it may depend on how you define minimal: conveyor generate javafx com.example.jfx-test && cd jfx-test ./gradlew jar conveyor make windows-app du -h output 71mb on disk. 31mb package size. That's a bit bigger than strictly necessary. It includes FXML and see the discussion of optional plugin modules elsewhere. However you can easily get to 150-200mb on disk by…

Yeah, removing javafx-media and javafx-web saves a ton. It's good to point that out. It's been a couple of years, so I'll need to revisit this again later and try again > It includes FXML and see the discussion of optional plugin modules elsewhere. Where is this? And do you know if it's still not possible to generate an .exe? I remember that while I was turned off by the final files sizes, what really made me drop jl…

Elsewhere in this thread (look at my other comments).

jlink itself just outputs a directory tree. If you want the user to be able to double click an exe then there are several options but two are:

1. Use Gluon Native Image. This will AOT compile your Java code and statically link JavaFX to give you a genuine single EXE program, with no JVM, no JIT compilation, and fast startup. However your app needs to be native-image compatible and I don't know if every app turns into a single EXE.

2. Use (surprise) Conveyor, which will make an EXE that when opened downloads, installs and then immediately runs your app using a bundled JVM. If your app is already installed then it'll do an update check and then open it. And of course your app can be then invoked from the start menu.

The latter isn't genuinely a single EXE of course but the UX is similar and it handles the common case of needing to update either your app, or your JVM, or both.

Re: Using jlink to cross-compile minimal JREs

#46

Earlier quoted context omitted.

Minimal Swing app is about 27mb compressed, 28mb with FlatLaf. That's for Windows. A bit smaller if you drop ECC and accessibility support. That 6mb is just for Dart right? I thought a minimal Flutter app is about the same size as a minimal Swing app.

thanks,yes it is dart only size,need measure flutter size vs swing as a single exe

A couple of years ago I did some experiments to see how small you could make HotSpot and still have something usable. I got it down to a 7mb download but that required some tricks:

- .tar.zstd

- A custom build of HotSpot that compiled out some optional features.

- It was just java.base, no swing

You can get smaller if you do DCE / tree shaking more aggressively, or use a custom JVM designed for size. The smallest I've seen was Avian which can produce GUI apps that are 1mb standalone binaries. It's abandoned unfortunately.

Re: Using jlink to cross-compile minimal JREs

#47
post #22

It's a pity that system wide JREs are not a thing anymore. I understand that it was difficult to get an updated JRE on the system in the early 2000s, but nowadays almost every computer is online - certainly one where you are currently downloading an application on - and automatic updates are commonplace. You used to be able to just double click on a .jar, and that was a Java application. And it would be trivial engin…

We already have that, it's called a package manager. The concept has a number of problems (multiple runtime versions for multiple programs, who pays for and controls the repository, etc etc).

> multiple runtime versions for multiple programs

For Java, the latest one. Current latest java still runs 20 year old jars.

> who pays for and controls the repository

The OS distributor.

Re: Using jlink to cross-compile minimal JREs

#48
post #24
post #10

These days, all Java runtimes are created with jlink, including the one that's bundled in the JDK, so it's worth it to take a few minutes to learn how to do it yourself for a custom image. The result is not only drastically smaller, but more secure, as the potential attack surface area is much smaller. If your application is modularised, it can become a part of the image, but, as the article shows, creating a custom…

How is modularization progressing in practice? Stuff like Hibernate, Spring, the big libraries. How easy is it for the average greenfield enterprise to start as a modular app? How easy is it for the average brownfield enterprise app started 10 years ago to convert to a modular app?

It's getting better to be sure.

It's definitely taken time for the libraries to catch up, but when 17 came out and put a kibosh on the work arounds folks relied upon when using libraries that were not properly modularized.

From a JakartaEE perspective, that's a different world. The containers were modular runtimes of their own sort anyway, many are built upon OSGI, etc. I don't think mainstream EE projects are using modular projects.

As a developer at the end of the line, building personal and in house projects, I don't personally get much value from the modular system. It's extra bookkeeping to manage, it's seems as much whack-a-mole of updating the module-info file as any deterministic plan. You mostly learn you have a problem when something won't load, making the whole thing rather reactive.

I don't really care about the JDK/JRE size, I don't distribute projects that way. They're just jars, or they're WARs for the container. If you have to send up the entire runtime, all the time, then sure there can be value. But as mentioned, you don't need a modular project to use jlink.

So, clearly, the JDK certainly benefits from this. But it's imposed from above on to everything, and I'm not that sure that everyone else gets real value from it.

Re: Using jlink to cross-compile minimal JREs

#49

This is awesome to know, I'm using Dart these days(java like language) that has a much smaller runtime(helloworld is 6MB), any one tried it with swing for GUI and see how large the final size is about.

I also use Dart to create native binaries! Just because it's so easy. I have a real CLI app that does quite a lot of stuff, and it's less than 8MB. And runs really fast! At least around as fast as a Java native app compiled with native-image (GraalVM), but I hate native-image because it takes MINUTES to compile and sometimes does not behave exactly like the JVM-version (Dart doesn't even need to compile, you can run from source, and when you want to compile to binary it still takes just a few seconds).

Re: Using jlink to cross-compile minimal JREs

#50
post #22

Earlier quoted context omitted.

We already have that, it's called a package manager. The concept has a number of problems (multiple runtime versions for multiple programs, who pays for and controls the repository, etc etc).

> multiple runtime versions for multiple programs For Java, the latest one. Current latest java still runs 20 year old jars. > who pays for and controls the repository The OS distributor.

"For Java, the latest one. Current latest java still runs 20 year old jars."

Not necessarily anymore. Many of the standard JVM features were removed in 11+ instances, so things like _some_ of the JVMs JMX APIs were removed for one reason or other. I'm not saying the removals weren't justified, simply clarifying that not all java applications written N years ago are still entirely supported.

Post reply on HN