Clojure's support for dynamic development incurs runtime costs that may be undesirable in certain production environments. These include:
Additionally, the indirection involved using a Var, especially via getting a reference to a Var via
Var.intern(String, String) makes Clojure-generated bytecode hard to analyze via programs like ProGuard.
Starting a Clojure program takes a significant amount of time, most of which is taken up by the Clojure runtime bootstrapping itself, i.e. loading and initialising namespaces and vars (see Why is Clojure bootstrapping so slow?). For long-running applications, this is probably not an issue. However, this is a problem in other scenarios:
Android applications should ideally load about as fast as Java or Scala applications. Currently, on a high-end telephone, a minimal Clojure program will take about one second longer, which is perceptible. In some cases, having a Java splash screen thrown up while Clojure bootstraps may be an acceptable solution, but that doesn't work for all programs.
Depending on the type of utility, Clojure's start time can dominate the time used to do the actual work. Current workarounds include using persistent JVMs, i.e. nailgun, or using ClojureScript with Node.js.
GAE imposes a strict sixty second time limit for responding to a request. If the application hasn't warmed up, Clojure's startup can take up a significant portion of that time, resulting in the initial request timing out.
Generally speaking, each time a Var is used within a function invocation, it's root binding must be retrieved. While this is a very simple operation, it does require reading a
volatile variable, which may impede optimisation. In some programs, this overhead is measurable. Currently, this best workaround for this is using a macro or
definline, but this results in code that is harder to read and write.
Clojure 1.5.1 uses over seventeen megabytes of heap size just starting a basic REPL. Much of this heap use results from Clojure simply loading up a lot of Vars which may or may not be used in a given program. For servers with gigabytes of RAM, this may just be noise. However, in more constrained environments, e.g. Android, this can be more of an issue.
Manual tree-shaking via commenting out portions of
clojure.core has shown significant reductions in heap use. Unfortunately, namespaces are currently atomic and cannot be easily broken up.
Clojure 1.5.1's JAR takes up about 3.5 megabytes. This isn't an issue for a lot of environments, but this can be an issue for mobile applications or Clojure as a library.
A number of mitigation strategies have been proposed to resolve one or more of the above issues:
usernamespace by default
volatileon a Var's root binding?
usernamespace by default
usernamespace is pure overhead. Removing this can make a difference at startup time and on memory use.