将App Engine Standard应用程序从Java 8迁移到带有捆绑服务的Java 11后的内存问题



有一个应用程序需要在应用引擎标准环境下从Java 8运行时迁移到Java 11运行时。我们决定采取最简单的方式,将服务捆绑迁移到Java 11,也就是说,部署仍然使用appengine-web.xml,而不是app.yaml

问题如下:使用Java 8, App Engine实例通常位于其可用内存的75-80%,并且从未发生过内存错误。自从迁移到带有捆绑服务的Java 11以来,实例处于90%+状态,即使对于非常轻的请求,错误"Exceeded soft memory limit of ... ... after servicing X requests total"也经常发生。

Q1:仅在应用程序的迁移版本中导致这些内存问题的原因是什么?

Q2:为什么迁移后的应用程序不向Cloud Profiler发送分析信息?

我对内存问题的唯一假设是存在内存泄漏。因此,我尝试按照文档中的指南对应用程序进行概要分析:

  1. 添加以下内容到appengine-web.xml:
<env-variables>
<env-var name="GAE_PROFILER_MODE" value="cpu,heap" />
</env-variables>
  1. 为服务帐户提供Cloud Profiler权限。

但是,Cloud Profiler页面仍然显示一个欢迎页面,其中显示没有配置分析代理的消息。

编辑:将实例类更改为更高的实例类是不可选项。

要在java 11/17中进行分析,您必须执行

<env-var name="JAVA_TOOL_OPTIONS" value="-agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true" />

我也注意到迁移后更高的内存使用率,并一直试图找出原因。分析器似乎对查找内存泄漏没有多大帮助。堆转储会更好,但在appengine中似乎还不可能。

分析器确实显示了总的内存使用情况,对于我的服务器,它只有大约100mb。这有点奇怪,因为实例内存将增加到400mb以上。这让我觉得可能是JVM本身使用了更多的内存。

我试着调优了一些参数,取得了一定的成功。当前正在使用串行垃圾收集器,并且正在尝试指定最大堆大小。

<env-var name="JAVA_OPTS" value="-XX:+UseSerialGC -Xms100M -Xmx100M" />

https://docs.oracle.com/en/java/javase/17/gctuning/available-collectors.html

最新更新