我有一个只需要最多的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周之前它仍然有效。
提前感谢您的快速回答!
答案 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应用程序显着不太可能崩溃。
这是否意味着您无法运行内存小于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-env
或manifest.yml
文件设置JAVA_OPTS环境变量一样简单。显然,如果你降低这些值,你需要注意不要太低,在这种情况下你最终会得到OutOfMemoryErrors。
注意:如果您将一个区域设置为未设置,例如堆或元空间,JBP将使用手动自定义后的剩余部分巧妙地计算它。
希望有所帮助!
答案 1 :(得分:1)
我不是云代工厂中java应用程序内存处理方面的专家,但从我发现的情况来看,我需要了解以下内容:
-Xmx
之类的JVM内存参数。您可以在manifest.yml中自己配置这些参数,但如果您想使用云代工厂的扩展功能,则不建议这样做。 您可以在清单中执行的操作是使用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.+ } }'