无法运行小于 512M 的 Spring Boot hello world(MVC 或 WebFlux)以及大多数非平凡应用程序在 Cloud Foundry 上至少需要 1G 的事实对用户来说非常令人沮丧,并给人一种错误的印象,即 Spring少于 1G 的内存无法启动。
我们正在与@dsyer 、Boot 团队和其他人一起做一些工作来优化 Spring Framework 和 Spring Boot,以减少 GC 压力并降低内存消耗,但我倾向于认为我们还可以改进 Cloud Foundry 以更好的方式处理这个问题。
我已经提出了关于内存计算规则的https://github.com/cloudfoundry/java-buildpack-memory-calculator/issues/24 。
另一点:如果通过计算应用程序中的所有.class
文件(包括其依赖项)来计算类的数量,那么对于没有非常细粒度的 JAR 粒度的 Spring 应用程序来说,它不是可靠的信息来源,并且会仅有效加载 Spring JAR 上可用类的一小部分。
这个问题在我们在 Spring Boot 2.1 中提供的优化以及我们目前正在为 Spring Boot 2.2 进行的优化中更加明显。
我的直觉是,典型用户知道他们的应用程序在本地需要多少Xmx
内存,我们也许应该默认使用该信息。
通过配置内存计算器,可以在512M以下运行。
以下清单对我有用(spring boot + webflux)。
applications:
- name: myapp
path: target/myapp-0.0.1-SNAPSHOT.jar
memory: 256m
env:
JAVA_OPTS: '-XX:ReservedCodeCacheSize=32M -XX:MaxDirectMemorySize=32M'
JBP_CONFIG_OPEN_JDK_JRE: '[memory_calculator: {stack_threads: 30}, jre: {version: 11.+}]'
一个普通的 webflux 应用程序实际上只运行 60MB 内存。
我是内存计算器的忠实粉丝,因为大多数开发人员往往只关心堆大小并获得意外的 OOME(例如 Metaspace),但我同意我们可以改进它。
计算器中的默认线程大小(300?)至少对于 webflux 来说太大了。
对于初学者来说,很难找到自定义内存大小的方法。
README 中用例的配置示例将非常有帮助。
@making我已经更新了这个问题的标题,以更清楚地说明它是关于(至少)引导应用程序的默认配置是次优的。 当然,使用 256M 和自定义配置运行引导应用程序是完全可能的,但在我看来,默认内存配置离准确很远,我希望我们在这方面取得一些进展,因为它影响了很多用户。
您提到的 WebFlux 应用程序的线程数确实是一个非常有趣的点,构建包可以通过检测它是哪种应用程序来提供额外的附加值。 这可能很棘手,因为某些 MVC 应用程序可以使用 Reactive WebClient
,但我相信我们可以做一些更聪明和准确的事情。
您的自定义内存配置突出了 IMO 自动配置机制中的问题。 如https://github.com/cloudfoundry/java-buildpack-memory-calculator/issues/24 中所述,如果我明确指定 Boot 应用程序有效使用的类数(8000 到 10000 之间),则生成的参数为-XX:ReservedCodeCacheSize=240M
,您在其中指定-XX:ReservedCodeCacheSize=32M
。 这种差异真的很大,我们可以做出更有根据的猜测吗?
此外,8000 或 10000 是引导应用程序有效使用的分类数。 如果构建包是根据应用程序中的类数+依赖项计算的,我倾向于认为指定给内存计算器的类数会人为地高(我仍然需要检查当前猜测的值,但构建包)由于 Spring Framework JAR 的性质。
我还想知道我们是否利用最新的 Java 8 和 Java 11 中提供的新容器内存选项。它们是为 Docker 设计的,但我想我们也可以在 Cloud Foundry 中受益。 尽管 CF 没有使用 Docker,Java 运行时是否知道我们正在容器中运行? 我们是否利用-XX:InitialRAMPercentage
、 -XX:MaxRAMPercentage
或-XX:MinRAMPercentage
?
这是一个棘手的问题@sdeleuze。 java-buildpack 是否使用 java 默认值,我们假设一些想法进入了 java 设置,默认情况下允许应用程序运行,更像是它们不在 CF 中运行时所做的那样? 或者 java-buildpack 是否更改了默认设置以改善初始体验,但是当应用程序没有按预期运行而不是在 CF 中时让用户搜索答案?
今天,java-buildpack 选择使用 java 和 tomcat 默认值作为今天的典型应用程序信任这些值。 我个人更喜欢这种方法,而不是更改可能以对用户不太明显/不明确的方式影响应用程序的 Java 默认值。
就新属性而言,我对RAMPercentage
属性的理解是,它们只是根据可用内存的百分比自动设置堆值。 没有考虑非堆内存要求,如代码缓存大小、线程堆栈大小、元空间、GC 内存开销等。这项工作仍然留给用户练习,以猜测他们的应用程序需要多少非堆内存。 我期待有一天 java 可以简单地正确管理所有内存池,以将应用程序保持在容器的内存限制内。 但我怀疑我们离这一点还有很长的路要走。
作为旁注,这是我为我的应用程序设置的 JAVA_OPTS 和 jre 配置,我需要在低内存和速度的情况下保持稳定。
-Xss256K -Xms1M -XX:+UseSerialGC -Djava.compiler=none -XX:ReservedCodeCacheSize=2496k -XX:MaxDirectMemorySize=1M
配置文件
stack_threads: 20
最有用的评论
通过配置内存计算器,可以在512M以下运行。
以下清单对我有用(spring boot + webflux)。
一个普通的 webflux 应用程序实际上只运行 60MB 内存。
我是内存计算器的忠实粉丝,因为大多数开发人员往往只关心堆大小并获得意外的 OOME(例如 Metaspace),但我同意我们可以改进它。
计算器中的默认线程大小(300?)至少对于 webflux 来说太大了。
对于初学者来说,很难找到自定义内存大小的方法。
README 中用例的配置示例将非常有帮助。