Two root causes for memory growing to 1.7GB and never shrinking:
1. No -Xmx limit (Dockerfile): JVM grew its heap without bound after
processing large uploads and never returned memory to the OS. Now capped
at 128MB with G1GC periodic GC every 30s to shrink when idle.
2. Broken HTTP Range (StaticResource): The server advertised
Accept-Ranges: bytes but didn't actually handle Range headers —
every request sent the entire .jsdos file (up to 1.2GB for GTA).
The OS cached the full file in page cache, which counts against
Docker container memory and persists after play stops.
js-dos v7 loads .jsdos via Range requests (lazy ZIP loading).
Now properly parses Range: bytes=start-end headers, responds with
206 Partial Content, and seeks to exact offsets in the file —
only the requested bytes stream through, keeping page cache minimal.
- Replaced Go stdlib server with Quarkus (RESTEasy Reactive + Jackson)
- 7 Java classes: Game POJO, GameService (JSON file I/O), 4 REST resources, static file serving
- Same JSON-per-game storage, same ZIP upload + bundle creation
- Same Svelte frontend (unchanged), built into the JAR via maven-resources-plugin
- Multi-stage Dockerfile: Node → Maven → JRE runtime