Swisscom云上的Java应用程序因OOM失败

Swisscom云上的Java应用程序因OOM失败,java,jvm,cloud-foundry,tomcat8,swisscomdev,Java,Jvm,Cloud Foundry,Tomcat8,Swisscomdev,我们有可部署在Swisscom云上的Java应用程序。 具有1.5 G RAM的实例。 我们正在使用CF的下一个参数来限制此应用程序的内存使用 [jre: { version: 1.8.0_+ }, memory_calculator: {memory_sizes: {stack: 228k}, memory_heuristics: {heap: 50, metaspace: 20, native: 50, stack: 10}}] 在实例下,当执行ps-ef | grep java时,我们

我们有可部署在Swisscom云上的Java应用程序。 具有1.5 G RAM的实例。 我们正在使用CF的下一个参数来限制此应用程序的内存使用

[jre: { version: 1.8.0_+ }, memory_calculator: {memory_sizes: {stack: 228k}, 
memory_heuristics: {heap: 50, metaspace: 20, native: 50, stack: 10}}]
在实例下,当执行
ps-ef | grep java
时,我们得到:

-Xms611500K -XX:MetaspaceSize=244600K -Xmx611500K -XX:MaxMetaspaceSize=244600K -Xss228
-XX:MaxDirectMemorySize=256m -XX:InitialCodeCacheSize=32m -XX:ReservedCodeCacheSize=64m 
-XX:CompressedClassSpaceSize=250m -XX:+UseCompressedOops -XX:+UseCompressedClassPointer
不幸的是,一段时间后,我们的应用程序进程被终止(“以状态137退出”)。我们尝试了不同的CF设置,但没有成功。尽管我们使用的内存有限,但我们的内存总是不足1.5千兆位

    2016-11-10T14:31:08.34+0200 [API/0]      OUT App instance exited with guid 
72a197e9-e222-43b5-9828-9553c1d58315 payload: {"instance"=>"", "index"=>0, 
"reason"=>"CRASHED", "exit_description"=>"2 error(s) occurred:\n\n* 2 error(s) 
occurred:\n\n* Exited with status 137 (out of memory)\n* cancelled\n* cancelled", 
"crash_count"=>1, "crash_timestamp"=>1478781068233690142, 
"version"=>"ebfced51-9973-434b-8ec0-79a8caa86b3b"}
崩溃之前,我们使用New Relic分析堆内存使用情况,我们发现您可以在下面看到:

在这里,大约4:30发生了
退出,状态137(内存不足)
。正如你所看到的,根本没有超出内存

在崩溃之前,当我在cf实例下执行
top
命令时,我得到了下一个:

7 vcap 10-10 6160764 1.357g 22528 S 27.37.4 3:09.52 java


究竟什么是错的?因为我看到java进程实际上使用了将近1.4G的RAM,但是从NewRelic图来看,没有这么大的内存使用量。

我假设您的应用程序正在崩溃,因为CF容器认为它使用了太多的内存。通过查看“cf事件”中的崩溃事件并确保它们是OOM崩溃,可以验证此假设。假设是容器使应用程序崩溃,我通常就是这样调整这种情况的

java_构建包非常努力地控制应用程序的内存使用。然而,似乎仍有一些应用程序中jvm找到了在配置选项之外分配内存的方法

当我遇到这个问题时,优化配置的最简单方法就是继续增加“本机”内存比率并减少堆,直到应用程序稳定为止。Native是jvm可能分配给buildpack无法管理的任何内容的全面存储桶


我还将删除“heap:600m”配置,因为这只会使启发式计算更加复杂,并可能使增加的本机百分比无效。

请参见此处获取退出代码:当您说“…尽管我们限制了使用的内存…”时,这是cloudfoundry中的限制吗?我想如果进程占用太多内存,那就是在扼杀进程。所以您还需要限制JVM中的内存使用Xmx限制JVM中的内存,您的意思是?是的,我限制了。我用New Relic监控后添加了更多的图形。我支持这个建议。你甚至可以考虑再向前走一步。增加应用程序的内存限制,但调整JBP,使其不会增加堆/元空间限制。这样做的目的是留下大量的“本机”内存(你可以稍后将其缩小),这就像一个缓冲区,为你的应用程序提供免费的、未使用的内存。如果你的应用程序足够强大,它将防止你的应用程序崩溃,然后你可以调查(jmap、profiler等)什么比你的应用程序(或者JVM)使用了更多的内存。哦,还要确保你使用jbp3.8+。对该版本中的内存计算进行了一些调整。如果你被旧版本卡住了,你可以
cf set env JBP_CONFIG_OPEN_JDK_JRE[内存计算器:{stack_threads:300,内存大小:{stack:228k},内存启发式:{heap:65,native:15,stack:10}]
来获得相同的更改。目前我正在进行下一个设置:为cf实例保留内存-1536m JBP_CONFIG_OPEN JRE:[jre:{version:1.8.0},内存计算器:{内存大小:{stack:228k},内存启发式:{heap:50,native:50,stack:10}]JAVA_选项:-XX:NativeMemoryTracking=detail-XX:MaxDirectMemorySize=256m-XX:InitialCodeCacheSize=32m-XX:ReservedCodeCacheSize=64m-XX:CompressedClassSpaceSize=150m-XX:+UseCompressedOops-XX:+UseCompressedClassPointersI甚至配置Tomcat使用直接缓冲区,其限制来自名为XX:DirectMemorySize的JAVA_选项年龄在继续增长。在使用jcmd summary命令进行进程时,我接下来看到了一件有趣的事情:本机内存跟踪:Total:reserved=1107812KB,committed=941036KB,但我在使用top命令时看到的不同:7 vcap 10-10 6037180 1.112g 22324 S 8.3 7.1 2:14.09 java类似于941MB而不是1.112,我无法解释很简单。如果你的应用程序正在泄漏内存,那么它将被杀死或最终运行到内存不足的状态。没有任何配置可以修复它。你唯一的选择是找到内存泄漏并修复它。如果内存使用与负载有关,你可能想限制负载。我认为杀死JVM不是一个好的选择,因为你失去了内存可以进行一些诊断,例如在内存不足时执行HeapDump。