Springboot App在docker上消耗内存过多

Mss*_*ssm 2 deployment tomcat memory-leaks docker spring-boot

尝试使用docker部署容器化 springboot 应用程序。这是我的Dockerfile

ROM openjdk:8
ADD app-1.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-Xmx64m", "-Xss256k", "-jar", "ecalio-landing.jar"]
Run Code Online (Sandbox Code Playgroud)

运行这样的容器

sudo docker run -d -m256m --restart=always server.tomcat.max-threads=5 --name=ecalio-landing
Run Code Online (Sandbox Code Playgroud)

部署后,我使用apache benchmark测试后端以及使用以下命令可以达到多少请求

ab -n 20000 -c 10 http://www.ecalio.com/
Run Code Online (Sandbox Code Playgroud)

基本上,试图知道后端是否可以一次达到 20000 个请求 10 ,因为我已将容器内存消耗限制256mb

容器从220mb开始达到245mb 左右,即使我重新运行相同的ab 命令,也不会再进一步

然而,当我尝试使用浏览器访问后端时每次刷新浏览器都会消耗 0.1mb,显然,一旦达到 256mb内存消耗,容器就会崩溃。

怎么会发生这样的事呢

我不希望我的容器消耗太多内存,它基本上是一个简单的应用程序,仅使用带有1 个实体模型的jpa,并且每次使用简单的控制器@Controller)调用/ url时仅执行 1 个检索请求,并且返回thymeleaf渲染的单个html 页面

我已经将 Java VisualVM 与我的应用程序一起使用(在没有 Docker 容器的情况下在我的计算机上本地启动),并且我可以清楚地看到我的应用程序没有任何内存泄漏,堆内存不会进一步超过 68mb 并使用堆总是被 GC 清除...

分析内存

Mss*_*ssm 8

经过这么多的挣扎,我找到了解决方案,这太荒谬了......

当这两个选项未传递给 JVM 时,即使将 -m 参数传递给容器的创建命令,它也会假定容器与主机共享相同数量的资源...

-XX:+UnlockExperimentalVMOptions
-XX:+UseCGroupMemoryLimitForHeap
Run Code Online (Sandbox Code Playgroud)

这意味着如果我使用 -m300m 创建一个容器来指定我的容器不应分配超过 300mb,jvm 仍然会认为该容器有权使用 2GB 内存(其中 2GB 是我机器的物理内存)

使用这些选项,我能够让我的应用程序在 256mb 容器上运行...当我知道有一次我的容器消耗了 800mb 时,真是太神奇了...

来源:

openjdk官方的docker镜像

有趣的文章

我的新 Dockerfile:

FROM openjdk:8
ADD app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-jar", "app.jar"]
Run Code Online (Sandbox Code Playgroud)

让JVM-server知道应用程序将在服务器环境中执行是有用的,这将导致一些变化,包括服务器环境的 GC 专用算法和一些其他行为,这些行为可以在官方文档中找到。

请注意,内存限制不需要 Xmx 或 Xss 或任何其他选项,因为 JVM 会自行修复所有问题(更多详细信息请参见下面的文章)

另一件需要知道的事情是,此配置在 OpenJDK 11 中自动完成。