swisscom cloud foundry spring boot app内存不足

Insufficient memory in swisscom cloudfoundry springboot app

我有一个 SpringBoot 应用程序,它只需要 max. 284 MB 内存。但我只能以最大启动应用程序。 768 MB 内存。即使我以后减少内存,我总是会收到以下错误:

[APP/PROC/WEB/0] ERR Cannot calculate JVM memory configuration: There is insufficient memory remaining for heap. Memory limit 384M is
less than allocated memory 672509K (-XX:ReservedCodeCacheSize=240M, -XX:MaxDirectMemorySize=10M, -XX:MaxMetaspaceSize=109309K, -Xss1M * 300 threads)

我已经在 cf 中使用相同的应用程序而没有这个问题。 cf有什么变化?在 2 或 3 周之前它仍然有效。

提前感谢您的快速回答!

我不是 cloud foundry 中 java 应用程序内存处理方面的专家,但据我了解,需要了解以下内容:

  • Java 应用程序通常通过 Java Buildpack 部署。如果你 不要在你的 manifest.yml 中定义一个 Version 它将占用 master 分支。由于主分支一直在变化,我假设 部署参数也可能会改变。
  • Java 构建包使用 Java Buildpack Memory Calculator 评估 JVM 内存参数,如 -Xmx。您可以在 manifest.yml 中自行配置这些参数,但如果您想使用 cloud foundry 的缩放功能,则不建议这样做。
  • 所以 - 当您定义允许您的 Cloud Foundry 应用程序使用 500MB 内存并且构建包计算器评估更多时,它可能无法工作并导致一些错误。

您可以在清单中执行的操作是使用内存计算器文档中提到的所有参数。例如,您可以给计算器一个提示,如果您需要更少的线程(例如 memory_calculator: { stack_threads: 100}

当您对 "hardcoding" 一些内存参数没有问题时:这里是我的 Spring Boot 2 / Java 9 应用程序的示例 manifest.yml,我使用了一个限制400 MB。它对我有用,但可能不是要立即复制的东西。这取决于您的应用程序。

applications:
- name: demo-app
  path: target/demo-app-1.0.0.jar
  instances: 1
  buildpack: https://github.com/cloudfoundry/java-buildpack.git
  memory: 400m
  env:
    JAVA_OPTS: '-XX:MaxMetaspaceSize=80780K -Xss512k -Xmx200M -XX:ReservedCodeCacheSize=16M -XX:MaxDirectMemorySize=16M'
    JBP_CONFIG_OPEN_JDK_JRE: '{ jre: { version: 9.+ } }'

I am already using the same app in cf without this problem. What has changed in cf? Before 2 or 3 weeks it still worked.

您必须升级到 Java Build Pack v4。使用 JBP v3,您可以推送具有较小内存量的应用程序,但使用该版本的构建包和小内存限制推送的应用程序也很容易崩溃。这样做的原因是因为 JBP v3 在 JBP 进行计算时没有考虑 JVM 使用的所有内存区域,因此虽然它会让您的应用程序启动,但应用程序稍后仍可能超过其内存限制。 JBP v4 计算内存的方式现在更加准确,并将 JVM 的所有内存区域都考虑在内。

最终结果是,对于 运行 RAM 小于 1G 的 JBP v4 应用程序,可以在暂存时看到以下错误,而 运行 512M 或更少的应用程序几乎肯定会看到暂存时出现此错误:

ERR Cannot calculate JVM memory configuration: There is insufficient memory remaining for XXXX

但是,Java 成功上线的应用 显着 不太可能崩溃。

https://discuss.pivotal.io/hc/en-us/articles/115011717548-Insufficient-memory-when-using-Java-Buildpack-4-0-

那么这是否意味着您不能 运行 Java RAM 小于 1G 的应用程序?不可以,但需要进行一些调整。这里列出了一些您可以调整以节省内存的东西。

  • 线程数。 JBP 假定您的应用程序将 运行 具有 250 个线程。这对于 Web 应用程序来说很常见,Tomcat 的内部内容大约有 50 个,请求处理有 200 个。您可以降低此值,但您需要确保您的应用程序不会超过您设置的任何线程数,否则您的应用程序可能会崩溃。对于您来说,这将通过 Spring Boot.

    调整 Tomcat 的配置

    JBP 的较低线程数示例:

    cf set-env my-application JBP_CONFIG_OPEN_JDK_JRE '{ memory_calculator: { stack_threads: 50 } }'

    Spring Boot application.properties:

    线程数减少的例子

    server.tomcat.max-threads=25

    注意:这只是请求处理线程。 Tomcat 本身有线程,您的应用也可以创建线程。您真的应该查看线程转储或 JVisualVM 以查看您的应用程序需要多少线程(即测量,不要猜测)

  • 线程堆栈大小 (-Xss)。这是一个传递给 JVM 的值,它控制每个线程需要多少内存。它默认为 1M,这是非常高的。在大多数情况下,您可以安全地将它降低到 160K,这是 Java 8 允许的最小值。如果您有 250 个线程并进行此更改,您将节省 (1M * 250) - (160K - 250) = 211M 内存。

    注意:如果您将线程堆栈大小降低得太多,您将在您的应用程序中看到 Whosebug 异常。如果发生这种情况,请保持冷静并提高该值,直到它们消失。

  • 降低保留代码缓存。这是 JVM 缓存 JIT 代码的地方。它默认为 24​​0M。您可以降低此值,但要小心,因为这绝对会影响性能。您还可以看到 errors at runtime if this value is not high enough.

    同样,最好衡量您的应用需要什么而不是猜测。您应该能够使用 JVM's NMT.

  • 进行测量
  • 您可以手动调整 JVM 使用的其他内存区域,如堆和元空间。使用 JBP v4,只需使用 cf set-env 或在 manifest.yml 文件中设置 JAVA_OPTS 环境变量即可。显然,如果您降低这些值,您需要小心,不要太低,在这种情况下,您最终会遇到 OutOfMemoryErrors。

    注意:如果您未设置一个区域,例如堆或元空间,JBP 将使用您手动自定义后剩余的任何内容巧妙地计算它。

希望对您有所帮助!