7

Exceeded soft private memory limit在应用引擎中的各种请求处理程序中偶尔遇到错误。我了解此错误意味着实例使用的 RAM 已超过分配的数量,以及这如何导致实例关闭。

我想了解错误的可能原因,首先,我想了解应用引擎 python 实例如何管理内存。我的基本假设是:

  1. F2 实例以 256 MB 开始
  2. 当它启动时,它会加载我的应用程序代码 - 比如说 30 MB
  3. 当它处理一个请求时,它有 226 MB 可用
    • 只要该请求不超过 226 MB(+ 误差范围),该请求就可以完成而没有错误
    • 如果确实超过 226 MB + 边距,则实例完成请求,记录“超出软私有内存限制”错误,然后终止 - 现在返回步骤 1
  4. 当该请求返回时,它使用的任何内存都会被释放 - 即。未使用的 RAM 回到 226 MB
  5. 无限期地对传递给实例的每个请求重复步骤 3-4

这就是我认为它会起作用的方式,但考虑到我偶尔会在相当广泛的请求处理程序中看到这个错误,我现在不太确定。我的问题是:

a) 步骤#4 发生了吗?

b) 什么可能导致它不发生?还是不完全发生?例如,请求之间的内存泄漏如何?

c) 存储在模块级变量中会导致内存使用泄漏吗?(我不是故意以这种方式使用模块级变量)

d) 我可以使用哪些工具/技术来获取更多数据?例如,在请求处理程序入口处测量内存使用情况?

在答案/评论中,请尽可能链接到 gae 文档。

[编辑] 额外信息:我的应用程序配置为threadsafe: false. 如果这对答案有影响,请说明它是什么。我打算threadsafe: true很快换。

[编辑]澄清:这个问题是关于 gae 对内存管理的预期行为。因此,虽然像“呼叫gc.collect()”这样的建议很可能是相关问题的部分解决方案,但它们并没有完全回答这个问题。直到我了解 gae 的行为方式之前,使用gc.collect()对我来说就像是巫毒编程。

最后:如果我把这一切都搞砸了,那么我提前道歉——我真的找不到太多有用的信息,所以我主要是在猜测..

4

3 回答 3

5

与任何其他标准 Python 解释器相比,App Engine 的 Python 解释器在内存管理方面并没有什么特别之处。因此,特别是,“每个请求”没有什么特别的事情发生,例如您假设的步骤 4。相反,只要任何对象的引用计数减少到零,Python 解释器就会回收该内存(模块gc仅用于处理垃圾循环——当一堆对象永远不会将它们的引用计数降至零,因为它们相互引用,即使没有可访问的外部引用)。

因此,如果您使用任何全局变量,内存可能很容易“在请求之间”“泄漏”(实际上,尽管从技术上讲它不是泄漏)——所述变量将在处理程序类及其(例如)get方法的实例中存在——即,你的观点(c),虽然你说你没有那样做。

一旦你将你的模块声明为threadsafe,一个实例可能碰巧同时服务多个请求(直到你在模块的配置文件部分中设置max_concurrent_requests的内容;默认值为 8)。因此,您的实例的 RAM 将需要是每个请求所需的倍数。automatic_scaling.yaml

至于(d),为了“获取更多数据”(我想你实际上是说,获取更多 RAM),你唯一能做的就是instance_class为你的内存大模块配置一个更大的。

使用更少的 RAM,有很多技术——它们与 App Engine 无关,与 Python 无关,尤其是与您的非常具体的代码及其非常具体的需求有关。

我能想到的一个特定于 GAE 的问题是ndb' 缓存已被报告泄漏 - 请参阅https://code.google.com/p/googleappengine/issues/detail?id=9610;该线程还建议了解决方法,例如关闭ndb缓存或移至旧版本db(不进行缓存且没有泄漏)。如果您正在使用ndb并且没有关闭它的缓存,那可能是您观察到的“内存泄漏”问题的根本原因。

于 2015-10-12T23:28:35.130 回答
2

第 4 点是一个无效的假设,Python 的垃圾收集器不会轻易返回内存,Python 的程序正在占用该内存,但在垃圾收集器通过之前不会使用它。同时,如果其他请求需要更多内存 - 可能会在第一个请求的内存之上分配新的内存。如果你想强制 Python 进行垃圾收集,你可以使用这里gc.collect()提到的

于 2015-10-06T23:01:35.400 回答
2

查看此问答,了解检查垃圾收集的方法和潜在的替代解释:Google App Engine DB Query Memory Usage

于 2015-10-06T23:26:56.347 回答