JavaCPP
github.com
github.com
I work on a large Java project (JRuby) and for us the largest component of time spent is on loading classes. Also, startup code is likely to run in the interpreter rather than being JIT compiled, which is also slower.
The solution we're looking at is ahead of time compilation. This avoids class loading and interpretation, and it does seem to solve the problem (we're back to ms startup time).
In V8 (Node.js) the majority of the core language and library features are effectively already AOT compiled as they're implemented in C++. In the OpenJDK (and most JVMs) a lot of this is implemented in Java, so that has to be loaded and interpreted rather than executed natively.
Also executing static code. A surprisingly large amount of code runs before you get to main().
That is, a big chunk of it is explicitly AOT compiled JS, a bit like a Smalltalk image.
If you look at the "Benefits" tab, you will see that startup will still take on the order of 1+ seconds, which is quite long IMO.
Also, would this work with Clojure? And are there open-source AOT compilers which work with Clojure?
It does a closed-world analysis on all your classes and compiles to native code. The JVM it uses is also written in Java, so is also compiled to native code. It uses the new Graal compiler for compilation at runtime (and actually also for the AOT part) so it also has high performance when running.
Details here http://medianetwork.oracle.com/video/player/2623645003001 or here http://chrisseaton.com/jvmls13-one-vm/jvmls13-one-vm.pdf (slide 19), but that's from 2013.
For oracle's VM they're working on a commercial feature https://www.youtube.com/watch?v=Xybzyv8qbOc
There also are things like nailgun which simply prestart a JVM and then delegate to the loaded JVM when you invoke some command. It may be a bit of a workaround, but if your use-case is to frequently start extremely shortlived programs that might be worth it.
Excelsior JET has been around forever, and works quite well, although it's very expensive. There was some discussion at the most recent Java One conference which suggested that Oracle will bring AOT to the JDK soon (probably prompted by the fact that Microsoft is doing this on the .NET side). However, there's as of yet no indication of timeline... or whether that will be in the core open-source JDK, or a paid enterprise feature.
Regardless, there is a lot that you can do, short of full-fledged AOT, to reduce the amount of work a JVM has to do at startup. Historically, some of the worst offenders have been libraries and frameworks that make heavy use of reflection. In recent years, alternatives have emerged that do more work at compile-time rather than relying on reflection at run-time.
For dependency injection, you might look at a compile-time solution like Dagger (http://square.github.io/dagger/), rather than traditional reflection-based packages like Spring or Guice. For logging, you might want to use SLF4J (http://www.slf4j.org/) rather than Apache Commons Logging. Use a database schema management solution like Flyway (https://flywaydb.org/) rather than letting an ORM screw around with your database schema every time on startup. Etc.
However, I really just don't understand the "Java is slow" gripe in the original comment. At my company, our Spring Boot-based services startup in around 8-12 seconds depending on the service. These are fairly complex application components too, no trivial "hello world" stuff. Sure, in my career I've seen some legacy apps that takes minutes to startup... but that's because a ton of cruft has been added over time. If you architect your application to initialize and communicate with a ton of external dependencies at startup every time, then startup is going to be slow no matter what language you're using.
It's just hard to take most of these gripes seriously. Java is well suited for server-side business application development, and systems integration. If you're using it in THAT context, and adhering to smart modern design principles, then it blows every other option away. If a Spring Boot or Dropwizard app is too slow to startup, then I'm sorry but you just don't know what you're doing.
If you're using Java for video game development, or some kind of desktop app, or embedded development on your Raspberry Pi Zero, then well... you're going to have a bad time, because Java is not very good for that even if you DO know what you're doing. Use something else in those contexts, for goodness sake.
Not sure I'd agree with that. It's obviously incorrect in a formal sense, and in an informal sense you could say that feature sets of so many languages overlapped somewhat so that the observation is useless.
In effect, it's using it like a server, for which the JVM is optimized.
BTW Why didn't Sun just serialize the whole image, retaining all those optimizations?
Anyway, I'm still curious how much faster running an AOT compiler on Clojure would be.
Clojure isn't really designed for this use case.
Which is just a few ms for pure Java.
If you mean it in association with Clojure, blame Clojure initialization code, not Java itself.
Also in general, the vanilla JVM startup is pretty quick... the slowness you're experiencing is probably "userspace" code.
sure the garbage collector make a difference but the big difference imho is how the VM interpret the bytecode.
In the JVM, the long startup time is because the bytecode is fully loaded, verified, etc. then interpreted
If you compare with other VM, like the AVM2 (ActionScript Virtual Machine 2), there the bytecode is considered as a stream, even if your program is many hundred of MB, the interpreter kick in much earlier.
It is explained in a presentation at Standord University by Rick Reitmaier from Adobe Systems
see at 31:35, https://youtu.be/BjYRzwDEIyw?t=1894 , he talk about startup time.
In my own experience working with AVM2 on my OSS project Redtamarin https://github.com/Corsaair/redtamarin , this startup time was key.
Wether you run the AVM2 from a shell script, a standalone executable or even as CGI under Apache, the avmshell which run, load, verify, interpret the bytecode, startup in matter of milliseconds.
But it is a trade, you could say
JVM: slow startup time, faster execution
AVM2: fast startup time, slower execution
The ideas behind it are really cool (auto generate JNI headers with annotations).
Ensure you checkout the presets: https://github.com/bytedeco/javacpp-presets
Another awesome thing built with it: