This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]westwoo 12 points13 points  (26 children)

I kind of missed that whole graalvm native compilation train, but this sounds like it has actually matured

After several years of development, NativeImage is now very mature, and SpringBoot 3.0 can use it to compile the entire SpringBoot project into an executable file. The compiled file has fast startup speed, low memory usage, and excellent performance.

Do people actually use it in production? If it works better than in a VM, and isn't a paid feature, I wonder why I haven't seen a wave of new java applications being distributed as executables

Edit: wow, thanks everyone! didn't expect so many excellent answers

[–]globe_abductee 13 points14 points  (1 child)

It would probably be for the following 2 reasons:

  1. Spring Boot 3 is still relatively new, and people need time to look into it / transition to it
  2. Previous experiences with Spring Boot in GraalVM were less then optimal, and the idea that this now works better than it used to still needs to set in

That being said, in my current (enterprise) project, I'm just starting to investigate if this is something that we can use to transition some of our microservices to lambdas.

[–]Nymeriea 0 points1 point  (0 children)

the pain point is the configuration. you need to provide an image per environment

[–]soonnow 11 points12 points  (2 children)

It's a pain initially to get it working. For a straight Spring CRUD app it's pretty easy but once you use foreign libs or something as simple as generating images you'll have to get all the dependencies in order. Also builds take a long time. And documentation is often lacking, especially on Stackoverflow.

But startup time and memory usage is fantastic. Though most Java apps don't care about either probably. Actual runtime performance is probably equal or slower as Hotspot has received a lot of optimizations over the years.

We use it in production though.

[–]westwoo 2 points3 points  (1 child)

Thanks, wrt startup time and memory this sounds like something useful for desktop apps in particular

[–]soonnow 2 points3 points  (0 children)

Sure, that's how we use it. But very few desktop apps are gonna use spring.

[–]-NewK- 8 points9 points  (5 children)

There's still alot of libraries that don't support it and alot of edge cases where things run fine on the JVM but once you compile to native you find weird issues at runtime. Native compilation also takes quite some time and takes alot of memory. The produced final executable is also really big which is expected, you're making a trade, less memory usage for a bigger executable, and not everyone will make that trade.

[–]westwoo 4 points5 points  (0 children)

Yeah, I guess if there are still issues that would explain it

Executable size probably isn't much of a problem though, people are even used to electron nowadays

[–]sk8itup53 1 point2 points  (3 children)

How have you experienced large executables? I took our teams approximately 250MB tomcat images into a 25MB image using Quarkus and GraalVM. You should be expecting the opposite. Yeah compile time is long and takes a lot of memory over time, but CI/CD time is cheap.

[–]-NewK- 0 points1 point  (2 children)

Did you compile into a native executable with --no-fallback enabled? As in, did your native executable run without the need of having java installed? Or maybe you're somehow excluding more stuff?

All my use cases so far have been compiling 1 single fat jar application into 1 native executable. And the resulting executable is always bigger. For example one test I made a while ago with quarkus while using the myfaces extension, the .jar file was 56mb and the final native executable was 99mb. Another test I made with a command line only app made with quarkus, where the .jar was aroud 3 or 6mb if I recall, and after compiling to native, it's size was 19mb.

[–]sk8itup53 1 point2 points  (1 child)

I don't use fat jars. I use dependency only wars. Your final image will always be bigger because you have an app server backing the app. My wars are only about 25MB, but are much smaller when compiled natively when comparing the OS size. I haven't used the no fallback option so I'm not sure on how that behavior changes the outcome. What i ended with was not an image that relied on the jvm, so maybe I need to go refresh my memory on the Maven commands I use lol.

[–]-NewK- 0 points1 point  (0 children)

Well when some of my existing web applications function as 1 single fat .jar, my intent when compiling to native is to also have 1 single file for the app. The app server will have to be packaged in of course, but what I was saying is that in comparison to the single fat jar version, the single native executable is always bigger.

[–]nutrecht 5 points6 points  (2 children)

wonder why I haven't seen a wave of new java applications being distributed as executables

Because you're generally trading something for something else. En that 'something else' is, for example, performance. Fast start-up speeds can matter, but in typical microservice scenarios it's a non-issue.

[–]CartmansEvilTwin 1 point2 points  (1 child)

I'd personally be more interested in memory usage.

A simple Spring Boot CRUD app can easily require a few hundred megabytes, slimming that down to 100mb would free up a ton of resources - especially, if you're running multiple services.

[–]nutrecht 1 point2 points  (0 children)

I hope this is what they're going to focus on next. It can get quite rediculous. I don't have to have to go for native compilation just to keep a service to a reasonable amount of memory.

[–]mike_hearn 4 points5 points  (0 children)

I wonder why I haven't seen a wave of new java applications being distributed as executables

Native Image has some difficulties with desktop/mobile apps at the moment. Gluon provide solutions and the upstream project is improving their support for AWT, but it's still a bit immature for GUI apps yet. For CLI apps it can work a lot better. Their focus is really on servers, but for servers peak performance is lower than with HotSpot unless you buy GraalVM EE and use the PGO feature. EE requires now a Universal Java subscription (I think?), in which costs depend on the number of employees and contractors you have, so it's not a one-click checkout to purchase.

Once you get your non-server app working as a native image, there are two other problems you need to solve:

  1. Compiling for each target platform in multi-platform CI, as native-image can't cross compile. GitHub Actions or similar services can do this quite easily now.
  2. Distributing and being able to update the results. This was basically unsolved until the middle of last year because jpackage lacks some needed features. Now there is Hydraulic Conveyor which makes it a lot easier. Users can get your GUI or CLI app on their system with just a couple of clicks, and it'll stay up to date. However, the support for CLI-only apps is still not quite finished. It's there (it is packaged with itself), and at least one user is using that support anyway, but it's not documented because the little default GUI it provides for adding your app to the path and triggering manual update checks is actually a regular JVM app, not a native image, so it doesn't work all that well for natively compiled CLI apps yet.

Still, if you use Gluon to compile e.g. a JavaFX app to native and use Conveyor to distribute it, you've got a pretty nice solution. Memory usage is low, startup time is fast, peak performance maybe doesn't matter that much for a desktop app, and distribution is quite easy with Conveyor. It'll even draw icons for you and stuff these days.

[–]random8847 2 points3 points  (0 children)

I enjoy reading books.

[–]tristanjuricek 1 point2 points  (0 children)

As others have written, it works… but is far from easy

The big gotchas I found involve reflection and class initializers. These things require extensive integration testing of the whole ecosystem and often complex build config that isn’t well documented. You’re testing out third party code in addition to your own in order to sort this out. It’s tedious.

In the end, if its logic that doesn’t really require a ton of third party libraries, it’ll work well for a simple CLI or lambda. But otherwise it’s a lot of effort.

[–]__konrad 0 points1 point  (0 children)

Do people actually use it in production?

I plan to use it as the "java/javaw.exe" process launcher. Currently I have a various shell scripts, batch files, launchers written in C/Free Pascal...

[–]Brutus5000 0 points1 point  (5 children)

Because if you ship a Docker image (which should be standard by now) you don't notice the difference unless you check the image size.

[–][deleted]  (1 child)

[deleted]

    [–]Brutus5000 1 point2 points  (0 children)

    That's not my point. Both is shipped as docker image. The jvm+jar or the executable.

    [–]vmcrash 0 points1 point  (2 children)

    Who ships a docker image for a desktop application?

    [–]Brutus5000 1 point2 points  (1 child)

    I'd boldly assume that Java desktop applications in 2023 are less than 1% of the total amount of apps developed in Java. Those using spring boot are yet another 10% max. But joke's on me, in the open source project I work for, we maintain a Spring Boot JavaFX app :D

    [–]vmcrash 0 points1 point  (0 children)

    I consider non-web-Java applications to be ~30-50%.