swisscom cloudfoundry springboot app中的内存不足

时间:2017-12-15 10:55:02

标签: java spring-boot memory cloudfoundry swisscomdev

我有一个只需要最多的SpringBoot应用程序。 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周之前它仍然有效。

提前感谢您的快速回答!

2 个答案:

答案 0 :(得分:5)

  

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

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

最终结果是,运行少于1G RAM的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-

这是否意味着您无法运行内存小于1G的Java应用程序?不,你可以,但这需要一些调整。这里列出了一些你可以调整以保存内存的东西。

  • 线程数。 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的RAM

    注意:如果您将线程堆栈大小降低太多,您将在应用中看到StackOverflow Exceptions。如果发生这种情况,请保持冷静并提高价值,直到它们消失为止。

  • 降低保留代码缓存。这是JVM缓存JIT代码的地方。默认为240M。您可以降低此值,但请谨慎使用,因为这绝对会影响性能。您还可以看到errors at runtime if this value is not high enough

    同样,最好衡量一下您的应用需求而不是猜测。您应该可以使用JVM's NMT

  • 进行衡量
  • 您可以手动调整JVM使用的其他内存区域,如Heap&元空间。使用JBP v4,就像使用cf set-envmanifest.yml文件设置JAVA_OPTS环境变量一样简单。显然,如果你降低这些值,你需要注意不要太低,在这种情况下你最终会得到OutOfMemoryErrors。

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

希望有所帮助!

答案 1 :(得分:1)

我不是云代工厂中java应用程序内存处理方面的专家,但从我发现的情况来看,我需要了解以下内容:

  • Java应用程序通常通过Java Buildpack部署。如果你 不要在manifest.yml中定义一个版本,它将占用主人 科。由于主分支一直在变化,我假设 部署参数也可能会发生变化。
  • Java Build Pack使用Java Buildpack Memory Calculator来评估-Xmx之类的JVM内存参数。您可以在manifest.yml中自己配置这些参数,但如果您想使用云代工厂的扩展功能,则不建议这样做。
  • 所以 - 当你定义你的云代工厂应用程序允许使用500MB内存并且构建包计算器评估更多时,它可能不起作用并导致一些错误。

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

当您使用“硬编码”某些内存参数时可以正常使用:这里是我的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.+ } }'