What is the runtime overhead of EK9 DI compared to frameworks?
← Dependency Injection · Ref: Q332
EK9 DI has near-zero runtime overhead because all validation happens at compile time and injection is simple field assignment.
SPRING DI OVERHEAD
1. REFLECTION: Spring uses reflection to discover and inject beans. Reflection is 10-100x slower than direct field access.
2. PROXY GENERATION: @Transactional, @Cacheable, and other annotations generate CGLIB proxies that add method call overhead.
3. CONTEXT STARTUP: Spring ApplicationContext initialization can take seconds to minutes for large applications.
4. CLASSPATH SCANNING: Component scanning examines every class on the classpath.
QUARKUS/MICRONAUT OVERHEAD
Both reduce startup time by moving work to build time, but still have more runtime overhead than EK9 due to CDI spec compliance and scope management.
EK9 DI OVERHEAD
1. COMPILE-TIME VALIDATION: All validation happens during compilation, zero cost at runtime.
2. SIMPLE FIELD ASSIGNMENT: Injection is direct field assignment during the prepare phase, equivalent to constructor assignment.
3. NO REFLECTION: No runtime reflection, no proxy generation.
4. NO SCOPE MANAGEMENT: Singleton-only means no scope resolution at each injection point.
5. STARTUP: Component creation is sequential field assignment, not graph resolution.
PERFORMANCE COMPARISON
Spring: seconds to start, reflection overhead per injection, proxy overhead per annotated method call.
Quarkus: sub-second start, reduced reflection, some proxy overhead.
EK9: near-instant start, zero reflection, zero proxy overhead, direct field access.
See Q227 for compile-time validation. See Q234 for lifecycle. See Q328 for Quarkus comparison.
Example
defines module qa.di.overhead defines component Calculator as abstract compute() as abstract -> input as String <- output as String? default operator ? FastCalculator is Calculator override compute() -> input as String <- output as String: "computed:" + input default operator ? Aggregator as abstract aggregate() as abstract -> items as String <- total as String? default operator ? SimpleAggregator is Aggregator calc as Calculator! override aggregate() -> items as String <- total <- String() total: calc.compute(items) default operator ? defines application ZeroOverheadApp register FastCalculator() as Calculator register SimpleAggregator() as Aggregator defines program OverheadDemo() with application of ZeroOverheadApp stdout <- Stdout() // === ZERO RUNTIME OVERHEAD: direct field access === aggregator as Aggregator! result <- aggregator.aggregate("1,2,3") stdout.println(result) stdout.println("No reflection, no proxies, no scope resolution")
Common mistakes
E08150 — Injection fields must use abstract types. Direct field assignment during the prepare phase resolves abstract types to concrete implementations with zero reflection overhead. See ek9 -h E08150 for details.
Incorrect:
calc as FastCalculator!
Correct:
calc as Calculator!
E08200 — SimpleAggregator injects Calculator, so Calculator must be registered first. Registration order determines creation order in the prepare phase. See ek9 -h E08200 for details.
Incorrect:
register SimpleAggregator() as Aggregator register FastCalculator() as Calculator
Correct:
register FastCalculator() as Calculator register SimpleAggregator() as Aggregator
Other ways to ask this
- Is EK9 DI faster than Spring DI?
- Does EK9 dependency injection add performance overhead?
- How does EK9 DI performance compare to other languages?
Coming from another language?
Java Spring: reflection-based injection, CGLIB proxies, seconds-to-minutes startup, BeanPostProcessor overhead. Quarkus: build-time resolution, sub-second startup, reduced but present proxy overhead. Micronaut: compile-time DI, minimal reflection. Go: no DI overhead (manual wiring). Rust: no DI overhead (manual construction). EK9: compile-time validation, simple field assignment, zero reflection, zero proxy, near-instant startup.
Keywords: performance, speed, cost, reflection, migrate, compile, dependency, startup, proxy, zero, inject, overhead, runtime