19

I have written a few small utility applications in Clojure that I compile into self-contained executable JAR files ("uberjars") using Maven and the maven-shade-plugin. These uberjars contain unpacked versions of clojure.jar and other libraries (i.e.: commons-cli) that the application depends on. They are convenient because I can send them to a customer without requiring that the customer install Clojure (all customers already have the JRE installed).

I have found that the Clojure applications take several seconds to start up, whereas similar applications written in Java start in sub-seconds on the same machines (time to show a usage message, for example).

I suspect that it is because Clojure is on-the-fly compiling some of the code in the clojure.core library as there is source code (.clj files) in the clojure.jar file.

Is there any way to precompile this source code? Can anything else be done to speed up startup performance? I have heard complaints from the customers about how long the startup takes (and they don't know or care that the application is written in Clojure or Java or Foobar).

Ralph
  • 31,584
  • 38
  • 145
  • 282
  • See also http://blog.ndk.io/solving-clojure-boot-time.html and http://dev.clojure.org/display/design/Improving+Clojure+Start+Time – Vadzim Sep 23 '16 at 20:43

3 Answers3

4

JVM (at least Oracle's HotSpot) makes very tricky thing to reduce startup time. It doesn't load to memory all program's classes and methods, it loads only resources it needs right now. There are not so many code needed to show a usage message or something like that, so only few functions are actually loaded and Java program gets started quickly. Moreover, HotSpot doesn't even compile these few functions - it uses JIT compilation (and other optimization) for the code, which is executed repeatedly. There's no reason to spend time to compile functions that will be executed only once, e.g. almost all startup methods, and HotSpot doesn't.

So, what about Clojure? I don't think you would like to rewrite Clojure's core to add similar functionality. Nevertheless, you can use same approach inside of your Clojure code. You said your utilities use several libraries, that can slow down startup. So, load libraries lazily as much as you can. For example, you can exclude :use option from your namespace definition and call explicit use in your principal functions instead. This won't reduce total time, but it will shift dalay to the moment, when it isn't so appreciable. You can even write small part of your program in Java and call Clojure code only when it is actually needed.

ffriend
  • 27,562
  • 13
  • 91
  • 132
  • Hello, the above mentioned solution would certainly lead to performance improvements, but at which cost ? ! The good news is that in Clojure 1.3, there is an experimental feature (alas "temporarily disabled" as is written in a recent commit in github) whose purpose is to enable "lazy loading" of compiled fns. – Laurent Petit May 17 '11 at 05:12
3

On the Clojure site there is a nice description of AOT compilation. This will already shave off some startup time.

Edit: there have been some efforts to run Clojure programs on a persistent JVM, thus reducing the start-up time. Look-up jark + jvm. However the site seem to have disapeared :(

Maurits Rijk
  • 9,789
  • 2
  • 36
  • 53
  • I already do AOT with my own code and only include the `.class` files in the JAR, but it seems that the clojure.core must include some source code that gets complied when the application starts, unless I am way off base and the slow start is due to some other cause. Were you suggesting rebuilding the clojure.jar with AOT? – Ralph May 16 '11 at 12:25
  • Don't worry, even though clojure.jar has some .clj files, it also has the corresponding .class files. The slow startup is mainly due to the JVM startup time, every time you execute your Clojure utility. – Maurits Rijk May 16 '11 at 12:34
  • 1
    "The slow startup is mainly due to the JVM startup time, every time you execute your Clojure utility." -- if that is true, why do Java applications start in under a second (Macbook Pro 2.66 GHz Core i7, 9GB RAM, OsX 10.6.7)? – Ralph May 16 '11 at 13:51
1

Of course, there is also the java -client JVM argument for improving JVM start up performance. This SO question goes into some detail about this topic.

Community
  • 1
  • 1
Julien Chastang
  • 17,592
  • 12
  • 63
  • 89