Opinion: First impressions of Rust coming from Java

Hey there!

I'm mainly a Java developer. I've just published a new article in Medium talking about how I was opening my mind lately to non-JVM stuff and how Rust came at that moment to my life.

That's my own personal experience, but I thought that this could be maybe a good starting point for a discussion about which were the things that attracted you most in your first developments with Rust, specially in opposition with your previous experiences with Java.

In my case, it's clear:

Performance and optimization: Specially the minimal size of the build, the ridiculous amount of memory used and also how fast everything works.

9 Likes

How big were your release bundles, usually?

Well, when you start to include libraries in your build, you reach easily a final .jar (already compressed) with a size of dozens of MB. I'm used to see fatJars of 30-50 MB, even more if you use SpringBoot or other kind of frameworks.

I was amazed when I made a --release build with cargo with 125 lib dependencies in total and the size of the executable was < 6MB

1 Like

Provide the following in your Cargo.toml to get them even smaller:

[profile.release]
lto = true
7 Likes

Wow! That made it only 3,6MB ! Almost half size!

What that flag does exactly ?

It enables optimizations at link time, after each dependency has been compiled independently.

2 Likes

Sounds like a lot of dead code removal and function inlining at link time

Great stuff, gets my current project down from 8.6MB to 6.5MB. 25% smaller.

You can also set codegen-units = 1 (default is 16) for full optimisation but the gains might not be worth it. You can also specify opt-level = 'z' if you prefer size optimisations.

[profile.release]
lto = true
codegen-units = 1
opt-level = 'z'
3 Likes

Embedded debug symbols can be fairly ginormous, too. If you're on a platform that embeds debug symbols in the binary (I vaguely recall that this isn't the case in Windows, at least), try running your binary through strip.

2 Likes

Durp, what? I always assumed a release build was stripped, never thought to check. Boom! strip get's things down to 3.7MB. A 57% shrinkage!

This is on Linux.

3 Likes

Also, support was recently added to rustc and cargo to have this done automatically! I am not sure when it's due to land in stable... maybe tomorrow?

3 Likes

It's not just debug symbols, it's symbols that are used for dynamic linking. In executables they're not really needed.

Don't know what is the current recommended way but in the olden days (a decade or two ago) it wasn't uncommon to copy symbols into a separate map file, strip symbols from the executable and deploy stripped executable without the map file.

Something like

nm --defined-only foo > foo.map
strip -s foo

# stash foo.map for later use
# deploy foo binary

If you needed to debug or print stack traces, you'd use the map file.

Personally I prefer to use nm+strip rather than let cargo do it for me. Cargo is just one step in the CI/CD pipeline. :slight_smile:

Yeah, I prefer that method, too.

It's also typical in RPM based distributions. The packaging process typically splits the symbols (and source) into a debuginfo package -- 99.999% of people don't end up examining core files with gdb, I suspect. :wink: (and the disk space savings is significant)

Do you have a reference to other release profile enhancements you would point people to?

Here's the official doc: https://doc.rust-lang.org/cargo/reference/profiles.html

2 Likes

You might be able to strip some extra bytes off with panic = "abort": https://doc.rust-lang.org/cargo/reference/profiles.html#panic

Wow, I didn't know about that one, and I've been writing Rust a while now. That's cool! :slight_smile:

I really liked the voice in your medium article. Very light hearted. I could feel how Java still had a place in your heart haha.

1 Like

lol. Absolutely, it's been such a long relationship XD...

Glad you liked the article! Many thanks for reading it