diff --git a/Dockerfile b/Dockerfile index 57a066a..afc2ffc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,8 +5,9 @@ LABEL org.opencontainers.image.source="https://github.com/sepal-contrib/se.plan" WORKDIR /usr/local/lib/seplan USER root +# libjemalloc2: allocator for the runtime (see ENV block near the end). RUN apt-get update && apt-get install -y \ - nano curl neovim supervisor netcat-openbsd net-tools git \ + nano curl neovim supervisor netcat-openbsd net-tools git libjemalloc2 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* \ @@ -28,6 +29,18 @@ RUN micromamba create -n seplan python=3.12 pip -c conda-forge -y && \ micromamba clean --all --yes && \ rm -rf ~/.cache/pip +# Run under jemalloc so freed per-session memory returns to the OS. glibc/pymalloc +# never release the arenas dented by per-session widget churn, so RSS ratchets to +# the peak working set and stays there (the production OOM); jemalloc purges free +# pages on a decay timer, so memory follows users back down. +# NOTE: if the .so is missing, LD_PRELOAD is silently ignored and PYTHONMALLOC=malloc +# is worse than stock — after any image change verify jemalloc is actually loaded: +# grep -c jemalloc /proc//maps # >= 1 +# Placed after the build layers so image builds don't run under the preload. +ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 \ + PYTHONMALLOC=malloc \ + MALLOC_CONF=background_thread:true,dirty_decay_ms:1000,muzzy_decay_ms:1000 + EXPOSE 8765 USER root