Sebastian Rask
11/19/2024, 12:13 PMorg.gradle.jvmargs=-Xmx512m
kotlin.daemon.jvmargs=-Xmx768m
But if I run the application in a docker container limited to 512mb I immediately run into an OutOfMemoryException.
Increasing the container memory limit to 956mb(!) ‘resolves’ the issue. But I can also see from the container stats that once running the application idles around 300mb.
I don’t have much experience with memory usage optimisation, but I guess I need to be more thoughtful about when I load and initialize my frameworks. (Is this a lazy process when running a JAR?)
I am looking for any pointers or experience regarding memory optimization.
Here is the full stack trace:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.Arrays.copyOf(Arrays.java:3537)
at java.base/java.io.ByteArrayOutputStream.toByteArray(ByteArrayOutputStream.java:185)
at kotlin.io.ByteStreamsKt.readBytes(IOStreams.kt:137)
[...] com.varabyte.kobweb.server.ApplicationKt.main(Application.kt)
Sebastian Rask
11/19/2024, 3:55 PMjava -Xmx512m -Dkobweb.server.environment=PROD -Dkobweb.site.layout=FULLSTACK -Dio.ktor.development=false -jar .kobweb/server/server.jar
Sebastian Rask
11/19/2024, 7:21 PM#-----------------------------------------------------------------------------
# Variables are shared across multiple stages (they need to be explicitly
# opted # into each stage by being declaring there too, but their values need
# only be # specified once).
ARG KOBWEB_APP_ROOT="app/site"
FROM openjdk:17-jdk-slim AS java
#-----------------------------------------------------------------------------
# Create an intermediate stage which builds and exports our site. In the
# final stage, we'll only extract what we need from this stage, saving a lot
# of space.
FROM java AS export
ENV KOBWEB_CLI_VERSION=0.9.16
ARG KOBWEB_APP_ROOT
ENV NODE_MAJOR=20
# Copy the project code to an arbitrary subdir so we can install stuff in the
# Docker container root without worrying about clobbering project files.
COPY . /project
# Update and install required OS packages to continue
# Note: Node install instructions from: <https://github.com/nodesource/distributions#installation-instructions>
# Note: Playwright is a system for running browsers, and here we use it to
# install Chromium.
RUN apt-get update \
&& apt-get install -y ca-certificates curl gnupg unzip wget \
&& mkdir -p /etc/apt/keyrings \
&& curl -fsSL <https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key> | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] <https://deb.nodesource.com/node_$NODE_MAJOR.x> nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
&& apt-get update \
&& apt-get install -y nodejs \
&& npm init -y \
&& npx playwright install --with-deps chromium
# Fetch the latest version of the Kobweb CLI
RUN wget <https://github.com/varabyte/kobweb-cli/releases/download/v${KOBWEB_CLI_VERSION}/kobweb-${KOBWEB_CLI_VERSION}.zip> \
&& unzip kobweb-${KOBWEB_CLI_VERSION}.zip \
&& rm kobweb-${KOBWEB_CLI_VERSION}.zip
ENV PATH="/kobweb-${KOBWEB_CLI_VERSION}/bin:${PATH}"
ARG BUILD_ENV="PROD"
ENV BUILD_ENV=$BUILD_ENV
WORKDIR /project/${KOBWEB_APP_ROOT}
# Decrease Gradle memory usage to avoid OOM situations in tight environments
# (many free Cloud tiers only give you 512M of RAM). The following amount
# should be more than enough to build and export our site.
RUN mkdir ~/.gradle && \
echo "org.gradle.jvmargs=-Xmx512m" >> ~/.gradle/gradle.properties
RUN kobweb export --notty
#-----------------------------------------------------------------------------
# Create the final stage, which contains just enough bits to run the Kobweb
# server.
FROM java AS run
ARG KOBWEB_APP_ROOT
COPY --from=export /project/${KOBWEB_APP_ROOT}/.kobweb .kobweb
ENTRYPOINT [".kobweb/server/start.sh"]
David Herman
11/19/2024, 10:13 PMDavid Herman
11/19/2024, 10:16 PMDavid Herman
11/19/2024, 10:17 PMDavid Herman
11/19/2024, 10:17 PM# Decrease Gradle memory usage to avoid OOM situations in tight environments
# (many free Cloud tiers only give you 512M of RAM). The following amount
# should be more than enough to build and export our site.
RUN mkdir ~/.gradle && \
echo "org.gradle.jvmargs=-Xmx512m" >> ~/.gradle/gradle.properties
David Herman
11/19/2024, 10:17 PMDavid Herman
11/19/2024, 10:19 PMSebastian Rask
11/20/2024, 6:52 AMNov 19 10:05:13 AM
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Nov 19 10:05:10 AM
2024-11-19 09:05:10.550 [main] INFO ktor.application - API jar found and will be loaded: ".kobweb/site/system/pixelpark.jar"
Nov 19 10:05:10 AM
2024-11-19 09:05:10.052 [main] INFO ktor.application - Autoreload is disabled because the development mode is off.
I have been able to reproduce the issue locally when I run the docker image with a memory limit like this:
docker run -m 512m kobweb_site
I just tried creating a dockerfile that simply copies the .kobweb folder that I build locally from clear build cache with the same command as the original dockerfile and runs it as usual.
In this case I also get OOM when running:
docker run -m 512m kobweb_site_local
BUT then I tried to modify the start.sh java args by adding the additional -Xmx512m
arg:
args="-Xmx512m -Dkobweb.server.environment=PROD -Dkobweb.site.layout=FULLSTACK -Dio.ktor.development=false -jar .kobweb/server/server.jar"
If I then build the image again (That just takes the local copy) and runs the image, I no longer get an OOM exception.Sebastian Rask
11/20/2024, 1:15 PMstart.sh
?Sebastian Rask
11/20/2024, 1:15 PMSebastian Rask
11/20/2024, 2:20 PM# Create the final stage, which contains just enough bits to run the Kobweb
# server.
FROM java AS run
ARG KOBWEB_APP_ROOT
COPY --from=export /project/${KOBWEB_APP_ROOT}/.kobweb .kobweb
# ENTRYPOINT [".kobweb/server/start.sh"]
CMD ["java", "-Xmx512m", "-Dkobweb.server.environment=PROD", "-Dkobweb.site.layout=FULLSTACK", "-Dio.ktor.development=false", "-jar", ".kobweb/server/server.jar"]
Though it does not seem like a good idea to ignore the start script (You might add other stuff to that in future releases.Sebastian Rask
11/20/2024, 3:20 PM# Prepend -Xmx512m to the args line in start.sh
RUN sed -i 's|^args="\(.*\)"|args="-Xmx512m \1"|' .kobweb/server/start.sh
This will allow me to keep using the start script, though modified to use the extra argSebastian Rask
11/20/2024, 5:12 PMDavid Herman
11/20/2024, 5:13 PMDavid Herman
11/20/2024, 5:14 PMDavid Herman
11/20/2024, 5:15 PMDavid Herman
11/20/2024, 5:23 PMSebastian Rask
11/20/2024, 5:25 PMDavid Herman
11/20/2024, 5:25 PMENV JAVA_TOOL_OPTIONS="-Xmx512m"
ENTRYPOINT [".kobweb/server/start.sh"]
Sebastian Rask
11/20/2024, 5:48 PMPicked up JAVA_TOOL_OPTIONS: -Xmx512m
2024-11-20 17:48:15.642 [main] INFO ktor.application - Autoreload is disabled because the development mode is off.
2024-11-20 17:48:15.656 [main] INFO ktor.application - API jar found and will be loaded: ".kobweb/site/system/pixelpark.jar"
2024-11-20 17:48:16.715 [main] INFO ktor.application - Loaded and initialized server API jar in 11ms.
2024-11-20 17:48:16.760 [main] INFO ktor.application - Application started in 1.148 seconds.
2024-11-20 17:48:16.951 [DefaultDispatcher-worker-1] INFO ktor.application - Responding at <http://0.0.0.0:8080>
David Herman
11/20/2024, 5:49 PMDavid Herman
11/21/2024, 2:11 AMDavid Herman
11/21/2024, 2:13 AM