Spring Boot vs Quarkus on a 768 MiB VPS

A follow-up to the 512 MB Spring Boot vs Quarkus experiment, comparing memory behavior under the same constrained JVM profile and application shape, with a bounded workload.

Question

How do equivalent Spring Boot and Quarkus applications behave when they share the same 768 MiB host budget and deliberately bounded JVM settings?

Setup

The comparison ran on Ubuntu 24.04 x86_64 in a VM configured with 768 MiB of RAM, of which the guest exposed approximately 703.5 MiB, plus one vCPU and 256 MiB of swap. Both applications used Eclipse Temurin 25.0.4.1+1, Spring Boot 4.1.1, Quarkus 3.39.4, file-backed H2, and the same Star Pulse-style application shape.

Both JVMs used the same profile:

-Xms16m
-Xmx80m
-Xss256k
-XX:+UseSerialGC
-XX:TieredStopAtLevel=1
-XX:ReservedCodeCacheSize=32m
-XX:+UseCompactObjectHeaders

A loopback-only Python fixture supplied deterministic GitHub-like responses. StatLite 0.4.2 monitored Spring, Quarkus, itself, and the host. This follows the earlier Spring Boot vs Quarkus on a 512 MB VPS experiment, using the same startup order: Spring first, then Quarkus.

Run

After both applications were ready, I sent one deliberate request to each, started monitoring, and ran a paired workload ten times. Each repetition sent one request to Spring, one to Quarkus, and then waited one second. The controlled observation lasted ten minutes.

This is a memory-behavior observation, not a throughput benchmark or a framework-wide ranking.

Results

CheckpointSpring RSSSpring swapQuarkus RSSQuarkus swap
Ready, pre-request228.2 MiB0.0 MiB164.6 MiB0.0 MiB
After one request223.9 MiB4.5 MiB163.8 MiB0.0 MiB
Post-workload221.3 MiB7.6 MiB164.4 MiB0.0 MiB
Intermediate210.1 MiB25.3 MiB172.1 MiB0.0 MiB
Midpoint, 5 minutes208.3 MiB27.6 MiB173.5 MiB0.0 MiB
After 10 minutes202.3 MiB34.3 MiB175.7 MiB0.0 MiB

Spring stayed roughly 27 to 65 MiB above Quarkus in RSS across the measured checkpoints and accumulated about 34 MiB of process swap. Quarkus recorded no process swap during the observation.

Spring Boot Quarkus

Each point is one checkpoint. The RSS chart uses a zero-based scale; process swap uses a 0 to 40 MiB scale.

Process RSS (MiB)

0 80 160 240 Spring ready: 228.2 MiB Spring after one request: 223.9 MiB Spring post-workload: 221.3 MiB Spring intermediate: 210.1 MiB Spring midpoint: 208.3 MiB Spring after 10 minutes: 202.3 MiB Quarkus ready: 164.6 MiB Quarkus after one request: 163.8 MiB Quarkus post-workload: 164.4 MiB Quarkus intermediate: 172.1 MiB Quarkus midpoint: 173.5 MiB Quarkus after 10 minutes: 175.7 MiB Ready 1 req Post Mid 5m 10m

Process swap (MiB)

0 20 40 Spring ready: 0.0 MiB Spring after one request: 4.5 MiB Spring post-workload: 7.6 MiB Spring intermediate: 25.3 MiB Spring midpoint: 27.6 MiB Spring after 10 minutes: 34.3 MiB Quarkus ready: 0.0 MiB Quarkus after one request: 0.0 MiB Quarkus post-workload: 0.0 MiB Quarkus intermediate: 0.0 MiB Quarkus midpoint: 0.0 MiB Quarkus after 10 minutes: 0.0 MiB Ready 1 req Post Mid 5m 10m 34.3
Six checkpoints from the controlled run. RSS remains lower for Quarkus, while Spring is the only process that accumulates swap.

The RSS lines appear to converge over the ten-minute observation, but RSS alone is misleading here. Spring's RSS fell by about 26 MiB while its process swap increased by about 34 MiB. Part of the apparent convergence therefore reflects Linux paging Spring memory out of RAM, rather than Spring simply reducing its memory footprint.

Validity checks

  • The paired workload completed with exactly ten HTTP 200 requests to each application.
  • Spring, Quarkus, and StatLite stayed active with zero restarts.
  • StatLite reported all monitored targets successfully with zero consecutive poll failures at closeout.
  • No matching kernel OOM or service-failure signals appeared in the collected closeout journals.
  • Final database files were 28 KiB for Spring H2, 32 KiB for Quarkus H2, and 172 KiB for StatLite SQLite.

What this suggests

For this application pair and this constrained VM, Quarkus used less resident memory and avoided process swap during the ten-minute run. Spring remained operational, but it had both a higher resident footprint and increasing process swap.

The conclusion is deliberately narrow. It does not establish that Quarkus is generally more memory-efficient or that it is a universal framework winner. The observation lasted ten minutes, and Linux paging is part of what was measured.

The same setup was repeated at 1 GiB with swap disabled. See the 1 GiB no-swap follow-up.

Dashboard views

These closeout screenshots show the monitored application and host dashboards. They provide operational context; the checkpoint table and chart above remain the primary measured evidence.

Evidence

The public experiment record contains the method, frozen inputs, workload contract, checkpoint data, polling summary, and selected screenshots.

Monitoring for this experiment was collected with StatLite, a lightweight self-hosted metrics dashboard for Spring Boot and Quarkus.