现在是2020年12月,在这个时间点 Java 在 Docker 容器中运行的内存限制已经有了明确的解决方案,此处做个记录。
JDK 10 引入了默认开启的参数 UseContainerSupport
,同时这个特性也被 backport 到 JDK1.8 的 8u191 版本。也就是说 8u191 和更后面的 JDK 都可以通过开启 UseContainerSupport
来支持 cgroup 看到 cgroup 的内存限制。
再结合 MaxRAMPercentage
来动态算一个堆内存上限就足够了,这个值具体看服务用到的堆外内存和线程的使用量,一般无脑给个 75/80 都没问题。具体程序用多少内存合适,正确实践一定是先预估一个偏保守的值,在环境里跑一下,然后结合实际请求量和监控来持续调节 kubernetes/docker 的内存限制数值。
下面是个 spring boot(layered jar) 工程打包为镜像的 Dockerfile 示例
FROM openjdk:15
WORKDIR application
COPY ./dependencies/ ./
COPY ./spring-boot-loader/ ./
COPY ./snapshot-dependencies/ ./
COPY ./application/ ./
ENV JAVA_OPTS='-Dspring.application.name=my-demo \
-XX:+UseContainerSupport \
-XX:MaxRAMPercentage=75.0 '
ENTRYPOINT exec java $JAVA_OPTS org.springframework.boot.loader.JarLauncher
最后还要再额外留意下,自 jdk9 (8u131)开始,这些跟容器支持的参数有过几轮变迁。如果没有多关注 upstream 或者搜了国内 CSDN 低劣二手文,很容易被拐到坑里去,比如看到下面这些参数,基本都是废弃或用不到的,不用再理会:
UnlockExperimentalVMOptions
UseCGroupMemoryLimitForHeap
UseCGroupMemoryLimit
MaxRAMFraction
MaxRAM
—— 引用自:李飘柔 https://www.zhihu.com/question/315793102/answer/1639340828
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]