Java performance: Native build vs vanilla .jar running on JRE

Have you ever compared the performance of a Java-based application running through the ๐—๐—ฎ๐˜ƒ๐—ฎ ๐—ฅ๐˜‚๐—ป๐˜๐—ถ๐—บ๐—ฒ ๐—˜๐—ป๐˜ƒ๐—ถ๐—ฟ๐—ผ๐—ป๐—บ๐—ฒ๐—ป๐˜ with a ๐—ป๐—ฎ๐˜๐—ถ๐˜ƒ๐—ฒ ๐—ฒ๐˜…๐—ฒ๐—ฐ๐˜‚๐˜๐—ฎ๐—ฏ๐—น๐—ฒ compiled using GraalVM?

For many years, I strongly associated Java with being an interpreted language that requires the JRE to run applications. However, a few years ago, something big happened, and now there are projects that can compile Java code into binary executables.

I heard some rumors that native builds might be significantly faster. It was interesting, but not compelling enough for me to start experimenting with it yet. However, we’re now reaching a point where projects like GraalVM have matured, and most issues have been addressed. So, itโ€™s been really fascinating to dive into this topic and explore modern options.

And you know what? The results of our tests are quite contradictory, and it seems we canโ€™t yet conclude if one approach will come out on top. However, weโ€™re ready to share some observations relevant to our use cases:

–         The ๐˜€๐˜๐—ฎ๐—ฟ๐˜๐˜‚๐—ฝ ๐˜๐—ถ๐—บ๐—ฒ of native code is faster (obviously!).

–         The ๐—บ๐—ฒ๐—บ๐—ผ๐—ฟ๐˜† ๐—ณ๐—ผ๐—ผ๐˜๐—ฝ๐—ฟ๐—ถ๐—ป๐˜ of native code is significantly smaller.

–         ๐—ฃ๐—ฒ๐—ฟ๐—ณ๐—ผ๐—ฟ๐—บ๐—ฎ๐—ป๐—ฐ๐—ฒ of native code in our test scenarios is slightly lower.

–         You need to be very careful with the ๐—ฑ๐—ฒ๐—ฝ๐—ฒ๐—ป๐—ฑ๐—ฒ๐—ป๐—ฐ๐—ถ๐—ฒ๐˜€ included in your binary during compilation, as the ๐˜€๐—ถ๐˜‡๐—ฒ ๐—ผ๐—ณ ๐˜†๐—ผ๐˜‚๐—ฟ ๐—ฝ๐—ฟ๐—ผ๐—ฑ๐˜‚๐—ฐ๐˜ might become unreasonably high.

–         You ๐—ฐ๐—ผ๐—บ๐—ฝ๐—ถ๐—น๐—ฒ ๐—ณ๐—ผ๐—ฟ ๐—ฎ ๐˜€๐—ฝ๐—ฒ๐—ฐ๐—ถ๐—ณ๐—ถ๐—ฐ ๐—ฝ๐—น๐—ฎ๐˜๐—ณ๐—ผ๐—ฟ๐—บ, so you canโ€™t run an x86 file on ARM – losing that luxury of cross-platform coding. Of course, you can compile for other platforms, but you’ll need to manage more files in the end and avoid mixing them up.

–         ๐——๐—ฒ๐—ฏ๐˜‚๐—ด๐—ด๐—ถ๐—ป๐—ด a running native process on the fly isโ€ฆ challenging ๐Ÿ™‚ You canโ€™t use most of the convenient tools to connect to it, so make sure to use good logging in your apps.

–         Running Java as a simple binary with no dependencies feelsโ€ฆ odd! But it also empowers you to do this ๐—ถ๐—ป ๐˜€๐—ถ๐˜๐˜‚๐—ฎ๐˜๐—ถ๐—ผ๐—ป๐˜€ ๐˜„๐—ต๐—ฒ๐—ฟ๐—ฒ ๐—ถ๐˜ ๐—ฝ๐—ฟ๐—ผ๐˜ƒ๐—ถ๐—ฑ๐—ฒ๐˜€ ๐—ฏ๐—ฒ๐—ป๐—ฒ๐—ณ๐—ถ๐˜๐˜€, such as when you are ๐—ฒ๐˜…๐—ฝ๐—ฒ๐—ฟ๐—ถ๐—ฒ๐—ป๐—ฐ๐—ถ๐—ป๐—ด ๐—ฎ ๐—ฅ๐—”๐—  ๐—ฑ๐—ฒ๐—ณ๐—ถ๐—ฐ๐—ถ๐˜. Additionally, you donโ€™t need to worry about security vulnerabilities in JAVA and deal with urgent upgrades.

We plan to dive deeper into this topic. Maybe with the proper tuning of compilation parameters, native could surprise us even more!