Supersonic Subatomic Java


Peter Palaga


Peter Palaga


  • An 8 ms demo
  • What is Quarkus
  • How it works
  • More Quarkus



$ which docker # make sure you have docker
$ mvn clean package -Pnative -Dnative-image.docker-build
$ ls -lh target/*-runner
-rwxrwxr-x. 1 ppalaga ppalaga 19M Mar 20 14:39 target/quarkus-hello
$ ./target/*-runner
INFO  [io.quarkus] (main) Quarkus 0.22.0 started in 0.004s.
INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

What is Quarkus




for writing Java, Kotlin and Scala applications

Embracing existing standards

Java EE MicroProfile Spring
  • Servlet
  • JAX-RS
  • CDI
  • Bean Validation
  • Transactions
  • Logging
  • Fault Tolerance
  • Health
  • JWT
  • Metrics (Prometheus)
  • OpenAPI
  • OpenTracing (Jaeger)
  • Reactive Messaging (Kafka, AMQP, MQTT)
  • Rest Client
  • Spring DI1
  • Spring Web1
  • Spring Data1

1) via compatibility layers
Well established

Libs and frameworks

Eclipse Vert.x Netty Apache Camel Infinispan Caffeine Keycloak
Kubernetes AWS Lambda Azure Functions Apache Tika ElasticSearch Kogito


  • MySQL, MariaDB
  • PostgreSQL
  • H2
  • MS SQL Server
  • FlyWay
  • Amazon DynamoDBβ€Ž
  • MongoDB
  • Neo4j




SayService say;

public String hello() {
    return say.hello();
@Inject @Stream("kafka")
Publisher<String> reactiveSay;

public Publisher<String> stream() {
    return reactiveSay;

Developer joy

  • Easy to start with:
    mvn quarkus:create or
  • Live reload:
    mvn compile quarkus:dev
  • Java, Kotlin or Scala
  • Maven or Gradle
  • Runners for JUnit 4 and 5
  • Isolation from GraalVM CLI/API

Container First

πŸ’Ύ Small size on disk βœ“ Small container images
πŸš€ Fast boot time βœ“ Instant scale up
πŸ”¬ Low memory footprint βœ“ More containers with the same RAM

Measuring memory

RSS1 = all RAM consumed by the process
$ ps -o pid,rss,command -p $(pgrep quarkus)
11229 12628 ./target/quarkus-hello


1) Resident Set Size

Memory (RSS)

Quarkus + GraalVM Quarkus + OpenJDK Traditional Cloud-Native Stack
REST 13 MB 74 MB 140 MB
REST+JPA 35 MB 130 MB 218 MB

Startup time

Modern frameworks use lazy initialization

"started" before all classes are initialzed

What matters:

Time to first request

Time to first request1/2

public class GreetingEndpoint {
    @GET @Path("/greeting")
    public String greeting(@QueryParam("name") String name) {
        return "Hello " + name;

Time to first request2/2

$ while [[ \
    "$(curl -s -o /dev/null -w '%{http_code}' localhost:8080/hello)" \
       != "200" \
  ]]; do sleep .00001; done
$ echo $(($(date +%s%N)/1000000)) && target/*-runner
INFO  [io.quarkus] (main) Quarkus 0.22.0 started in 0.035s.
INFO  [io.quarkus] (main) Installed features: [cdi, resteasy, resteasy-jsonb]
$ expr 1552931436637 - 1552931436155
482      # Time to first request in milliseconds

 Time to first request


Container density

in cloud environments

How it works

Traditional app server

  • Hundreds of classes run only during the boot
  • Later unused
  • Still occupy memory

XML parsers, annotation lookups, management model, ...


Build time boot

As much work as possible done at build time

Output: recorded wiring bytecode

Build time CDI (1/2)

Build time CDI (2/2)

// User beans
class Catalog {

  Pricing pricing;

  void init() {}

class Pricing { ... }

// Metadata (generated as bytecode)
class Catalog_Bean {

  Pricing_Bean pricingBean;

  Catalog create() {
    Catalog catalog = new Catalog();
    catalog.pricing = pricingBean.create();
    return catalog;

class Pricing_Bean {...}

// The "main" class (generated as bytecode)
class Application {
  static Map<String, Bean> beans = new ...Map();
  static Map<String, Supplier<Object>> appContext = new ...Map();
  static {
    // Wire the beans
    Pricing_Bean pricingBean = new Pricing_Bean();
    beans.put(Pricing_Bean.key, pricingBean);
    Catalog_Bean catalogBean = new Catalog_Bean();
    catalogBean.pricingBean = pricingBean;
    beans.put(Catalog_Bean.key, catalogBean);

    // Some beans can even be instantiated already
    Pricing pricing = pricingBean.create();
    appContext.put(Pricing_Bean.key, () -> pricing)
    Catalog catalog = catalogBean.create();
    appContext.put(Catalog_Bean.key, () -> catalog)

Wiring code invocation

Decided by extensions

static initializer OR main()
preferred access to files,
sockets, etc.

Build oriented container

Quarkus extensions

  • Units of Quarkus distribution (your Maven deps)
  • They configure, boot and integrate a lib/framework into a Quarkus application
  • Make the code lighter to run on a JVM
  • Make the code fit for the GraalVM

Quarkus Extensions ecosystem

  • New extensions are welcome!
  • Follow the guide for extension authors
  • Can be developed externally
     β†’ e.g. Camel Quarkus
  • Soon: 3rd party extensions on and in the Quarkus universe BoM

Two distinct things:

  1. Graal compiler (AoT or JIT)
  2. GraalVM - the polyglot VM
In this presentation:



Graal compiler



AoT1 compilation with GraalVM

1) Ahead-of-time (1/3)

AoT compilation with GraalVM


  • Static analysis
  • Closed world assumption
  • Dead code elimination:
        classes, fields, methods, branches

AoT compilation with GraalVM


$ native-image -jar my-app.jar
$ ./my-app
πŸš€  Fast process start
πŸ”¬  Less memory
πŸ’Ύ  Small size on disk


GraalVM GraalVM

Dynaminc Classloading

Deloying jars, wars, etc. at runtime impossible

GraalVM GraalVM


+ other native VM interfaces

No agents

JRebel, Byteman, profilers, tracers, ...

GraalVM GraalVM


+ other native VM interfaces

  • No Java debugger
  • Native debugger (GDB) still works
  • DWARF debug symbols
    • Inserted only by GraalVM enterprise
    • Allows stepping through your java code
GraalVM GraalVM


Security Manager

finalize() (deprecated anyway)

InvokeDynamic and MethodHandles

GraalVM GraalVM


Requires registration via native-image CLI/API

@RegisterForReflection in Qarkus

GraalVM GraalVM


Require registration via native-image CLI/API

  • Dynamic proxies
  • Resources
  • JNI, Unsafe Memory Access, ...
GraalVM GraalVM

Static init


Build time OpenJDK instance:

  • Resolve classes, run "safe" static initilizers
  • Take a snapshot of the produced heap
  • Store it in the executable
GraalVM GraalVM

Static init



no file handles, sockets, threads

More Quarkus!


  • Either have docker (easier)
  • Or export GRAALVM_HOME=...
$ mvn clean package -Dnative -Dnative-image.docker-build
$ ls -lh target/*-runner
-rwxrwxr-x. 1 ppalaga ppalaga 19M Mar 20 14:39 target/quarkus-hello
$ ./target/*-runner
INFO  [io.quarkus] (main) Quarkus 0.22.0 started in 0.005s.
INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

Discover extensions

$ mvn quarkus:list-extensions
[INFO] Available extensions:
[INFO]   * Hibernate ORM (io.quarkus:quarkus-hibernate-orm)
[INFO]   * Hibernate ORM with Panache (io.quarkus:quarkus-hibernate-orm-panache)
[INFO]   * Hibernate Validator (io.quarkus:quarkus-hibernate-validator)

Add an extension

$ mvn quarkus:add-extension -Dextensions=hibernate-orm-panache


Makes simple Hibernate ORM easy

public class Person extends PanacheEntity {
    public String name;
    public LocalDate birth;
    public PersonStatus status;

Panache persist

// Create a person
Person person = new Person(); = "Stef";
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1);
person.status = Status.Alive;

// Persist and delete
if (person.isPersistent()){

Panache Queries

List<Person> allPersons = Person.listAll(); // All persons
Person p = Person.findById(personId); // Specific person by ID
// Living persons
List<Person> livingPersons = Person.list("status", Status.Alive);

// Count
int countAll = Person.count();
int countAlive = Person.count("status", Status.Alive);

// Delete
Person.delete("status", Status.Alive);

More Panache

  • Paging
  • Sorting
  • Simplified query language
  • Autogenerated DAO/Repositories

Quarkus wrap up


  • Good old Java
  • Good old standards and libs
  • Efficiency level of Go language


Makes Java the choice #1 for the cloud and serverless

Quarkus Links