20 June 2021

For a couple of years now, I’ve been working on a self-hosted family budgeting application called Twigs. Seeing as I’m an Android developer, I spend most of my days writing Java and Kotlin. Thus, it seemed like a good idea to stick with the languages I’m most comfortable with for my backend solution. After doing a little research, it seemed to me like Spring Boot was quite popular, so I figured I’d also be doing myself a favor by learning something I could possibly apply on the job someday. Unfortunately, my simple app frequently occupies around 500MB of RAM on my small VPS with only 2GB of RAM total, and it’s not the only server I have running there, so I’ve been quite discontent with this. I have been considering rewriting the backend in Go or Rust to reduce the memory footprint of the app, but even for such a small application, that’s no small feat. In an effort to save myself some time and energy rewriting the whole thing, I’ve been looking around for ways to reduce the memory consumption of this app. Much to my surprise I found quite a simple solution that had a massive impact. Here was my Dockerfile before, where the app would frequently idle at around 500MB of RAM usage:

FROM openjdk:14-jdk as builder
MAINTAINER William Brawner <me@wbrawner.com>

RUN groupadd --system --gid 1000 gradle \
&& useradd --system --gid gradle --uid 1000 --shell /bin/bash --create-home gradle

COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN /home/gradle/src/gradlew --console=plain --no-daemon bootJar

FROM openjdk:14-jdk-slim
EXPOSE 8080
COPY --from=builder /home/gradle/src/api/build/libs/api.jar twigs-api.jar
CMD /usr/local/openjdk-14/bin/java $JVM_ARGS -jar /twigs-api.jar

Here’s the updated Dockerfile for the same app with much less memory usage:

FROM openjdk:14-jdk as builder
MAINTAINER William Brawner <me@wbrawner.com>

RUN groupadd --system --gid 1000 gradle \
&& useradd --system --gid gradle --uid 1000 --shell /bin/bash --create-home gradle

COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN /home/gradle/src/gradlew --console=plain --no-daemon bootJar

FROM adoptopenjdk:openj9
EXPOSE 8080
COPY --from=builder /home/gradle/src/api/build/libs/api.jar twigs-api.jar
CMD /opt/java/openjdk/bin/java $JVM_ARGS -jar /twigs-api.jar

The change might be easy to miss, so here’s the breakdown: I have two containers involved in the build process: the first takes in the source code and compiles it into a JAR file, then the second container copies that JAR file out and simply executes it. The change I made to reduce the memory was simply going from OpenJDK to OpenJ9, which brought my memory usage down from around 500MB while idle to around 150MB idle. While that’s still a bit more than I’d like for a super simple app, it’s little enough that I can stop worrying about it for the time being. I’ve had this running for a few days now without any noticeable side-effects, so I’m hoping this will be a long-term solution for me. Should anything come up though, I’ll be sure to write a follow-up post in the future.


Questions? Concerns? Thoughts? Suggestions? Get in touch