Performance Optimization
criterium ((crit/quick-bench (f))), clj-async-profiler (flame graphs), JFR/VisualVM
(set! *warn-on-reflection* true) and add type hints (^String, ^long) Avoid boxed math in hot loops
(set! *unchecked-math*:warn-on-boxed), primitive hints ^long/^double on fn args (up to 4) Transients for batch building
(persistent! (reduce conj! (transient []) xs)) No intermediate collections Choose the right collection
Vectors for indexed access, sets/maps for lookup, java.util collections or arrays for hot mutable loops Avoid laziness overhead where needed
reduce, into, run!, mapv are eager Use records/protocols for hot dispatch Faster than multimethods on hot paths Memoize pure expensive functions memoize, core.memoize (LRU/TTL)
pmap, reducers (r/fold), claypoole, virtual threads Heap size, GC choice (G1/ZGC), AOT compilation for startup time, GraalVM native-image
(require '[criterium.core :as crit])
(crit/quick-bench (reduce + (range 1000000)))
(defn sum-squares ^long [^longs arr]
(let [n (alength arr)]
(loop [i 0 acc 0]
(if (< i n)
(recur (inc i) (+ acc (* (aget arr i) (aget arr i))))
acc))))
(sum-squares (long-array (range 1000))) ; 332833500
(require '[clojure.core.reducers :as r])
(r/fold + (r/map inc (vec (range 1000000)))) ; parallel fold over a vector