In an unrelated thread, someone posted this quote from the Mithril documentation on the differences from React, which sums it up pretty well: https://news.ycombinator.com/item?id=22777320
Java and React are fast by bringing a lot of sophisticated (heavy!) machinery. Nim and Mithril are fast by being small and simple.
For example, the JIT makes Java fast – eventually. But initially it's interpreted and slow, with the additional overhead of bringing up the JIT compilation machinery in the background. AOT compiled code reaches its normal speed from the start. So Java programs take a while to get fast, which makes them feel heavy.
Startup is slow. Java 11 is slower than Java 8 which is slower than Java 6. Class-data sharing can make it faster – sometimes. You still have to load all that data, so when it's not cached in RAM and you have a slow disk it's still slow. A smaller program is always fast to load. This makes Java feel heavy.
When it comes to memory, Java does clever optimizations like escape analysis at runtime so that the programmer doesn't have to bother with deciding between allocating on the heap or the stack. This can also make it fast in certain scenarios, after warm-up, but a language with explicit value types can be made fast from the start. (Which is why Project Valhalla is coming.)
The solution to that is to cache/save a pre-compiled binary on disk/persistent storage. This is what modern Android does.
You would just essentially need an installation step, where you compile the binary (maximally optimized for the architecture that it's running on), and save that to disk. All of the problems you described disappear with that -- no startup/AOT delay nor any JIT compilation delays.
Pre-compiling stuff is a small price to pay for the benefit of better-optimized higher-performance execution.
Another thing: you could do memory safety and other static analyses and security checks during the pre-compile/install phase. There's a lot of benefits to that.
For e.g. if you are able to statically verify and guarantee (ie mathematically provably) that the code will not commit any memory violations, then you could optimize away many of the bounds and other related checks. These sorts of verification must be done on the machine that is actually executing the code, since you can't simply trust a third-party, and must yourself verify such assurances/claims.
Sure, an AOT compiler for Java would solve some of these issues, at the cost of larger binaries and loss of the dynamic runtime optimizations that make Java fast for long-running programs (which is why Android uses a combination of AOT and JIT). Some people on this site often point out that expensive commercial AOT Java compilers have been around for a long time. JetBrains even used to provide an AOT-compiled binary of the Kotlin compiler for a while.
However, you were asking why people consider Java to be heavy. When people normally use or talk about Java, Java means a JRE derived from Sun's Java implementation. If you download Java to run the Kotlin compiler or IntelliJ, you're not downloading the Android runtime or some hypothetical AOT compiler - you're using something based on OpenJDK, which suffers from the heaviness I described.
Java and React are fast by bringing a lot of sophisticated (heavy!) machinery. Nim and Mithril are fast by being small and simple.
For example, the JIT makes Java fast – eventually. But initially it's interpreted and slow, with the additional overhead of bringing up the JIT compilation machinery in the background. AOT compiled code reaches its normal speed from the start. So Java programs take a while to get fast, which makes them feel heavy.
Startup is slow. Java 11 is slower than Java 8 which is slower than Java 6. Class-data sharing can make it faster – sometimes. You still have to load all that data, so when it's not cached in RAM and you have a slow disk it's still slow. A smaller program is always fast to load. This makes Java feel heavy.
When it comes to memory, Java does clever optimizations like escape analysis at runtime so that the programmer doesn't have to bother with deciding between allocating on the heap or the stack. This can also make it fast in certain scenarios, after warm-up, but a language with explicit value types can be made fast from the start. (Which is why Project Valhalla is coming.)