I think for Server-Application Scala on the JVM will probably beat Scala-Native. The benefits of Scala-Native over Scala JVM are:
- faster startup time
- (drastically) lower memory footprint
- fine hand-tuning of you application
All these things are not super important in server-applications. For example Java trades memory for throughput (higher memory footprint, but also higher throughput. These usually go hand in hand.).
You could always bundle the jre, and with Java 9 one can even make use of the newly introduced linker to create a customized image just with the relevant classes.
The large memory footprint of the JVM is memory for classes, profiles, things like that. Those are used to create optimised code and to recover when optimisations were too optimistic. When your program is optimised and running in steady state, this memory isn't actively used and so doesn't contend with your application memory and so has no impact on cache efficiency.
This sounds like a plausible explanation, but is this verified/verifiable? Are there memory profilers that can show me the relative sizes of the young/old/permanent generation segments of the GC?
I'm always blown away at the memory usage of JVM apps. Part of it is the fact that java has encouraged insanity-inducing inheritance hierarchies...but also it is incredibly hard to do dead code optimization on for such a static (type and compilation model) language (I blame dymanic classloading, but that's more of a guess than anything). Maybe what you're saying is the reason we don't see noticable GC pauses until you start seeing large amounts of data...but it is still a huge pain for low memory environments like phones, embedded devices, IoT, etc. And while memory usage is always gonna be higher on a GC'd language, the JVM still consumes vastly more memory than other languages like OCaml, D, Go, etc.
Yes, it's called "perm gen cache," or something like that, on any standard JVM profile. This roughly represents the memory used by the type system. It can get pretty high if you are doing something like auto-generating types (GUI, build systems, etc)
In general (not for server apps), two major benefits of Scala Native are:
- Predictable latency if desired (optional GC)
- Very low call overhead for C ABI
As to your point about memory use, Java trades memory for convenience, not performance. GC requires substantially more memory for similar performance. I read an IBM blog (which I can't find at the moment) within the last week which showed a Swift web service running slightly faster than Java, but using only half the memory.
The following comparison is also interesting, with a JSON serialization example in Swift outpacing Spring/Java by a factor of ten... This is also running on Linux instead of macOS.
To be fair, in that list, the spring entry didn't exactly run circles around the competition either. It's somewhere between the better PHP contenders and even behind grails (which can be pretty accurately described as spring with layer of slowness added on top). Really looks like there is something unfortunate going on with the idiomatic way to implement those examples on spring.
I used the JVM on the 512MB DO instances and containers and they run fine. I think for containers there are other issues (most likely you are going in a micro service-direction where latency is eventually going to be important, so picking another JVM GC-algorithm might be suitable). There may be applications for which the 512 instances and JVM are not suitable, but you can most likely just upgrade the instance.
Many things pointed out in this article apply to just about every managed language runtime. Implement a TreeSet in any language and you'll see the same overhead from object headers, memory alignment, etc. Java has some oddities that cause it to waste extra memory, but off the top of my head the only I can think of is 16-bit character Strings. Java 9 is supposed to help with that by allowing Strings to internally store utf8 characters.
I do like the slide though showing that people tend to assemble abstractions together and completely lose sight of the performance costs of what they are doing. There's also the fallacy commonly held by many that because someone took the time to write a framework or library, they must have also taken the time to ensure it's optimized well.