Performance Tuning
Use @CompileStatic for hot paths. It removes dynamic dispatch and is often 2–10x faster for CPU-bound code. Apply it per class or globally via a compiler config script.
invokedynamic is the default (Groovy 4 made indy mandatory). Keep JDK and Groovy up to date for JIT improvements.
Prefer primitive types (int, long, double) in typed code. Avoid unnecessary BigDecimal math in tight loops (use double literals with d or typed double variables).
Avoid creating closures inside hot loops. Avoid excessive metaClass changes (they invalidate call-site caches).
Use StringBuilder (<<) for building strings in loops. Avoid GString concatenation in hot paths.
Prefer for loops or Java streams in performance-critical code. GDK iteration with closures is convenient but has overhead (it's mitigated by @CompileStatic).
Collections: choose the right type (ArrayList vs LinkedList, HashMap vs LinkedHashMap) and size them up front.
Startup time: precompile scripts (groovyc), use GroovyScriptEngine caching, or move to static compilation + AppCDS / GraalVM native image for CLIs.
Measure with JMH (there's a Groovy JMH Gradle plugin), async-profiler, VisualVM, and JFR (Java Flight Recorder).