app引擎(python)如何跨请求管理内存(超出软私有内存限制)

tom*_*tom 7 python memory google-app-engine google-app-engine-python

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

我想了解可能导致错误的原因,并且首先,我想了解app引擎python实例应该如何管理内存.我的基本假设是:

  1. F2实例以256 MB开头
  2. 启动时,它会加载我的应用程序代码 - 比方说30 MB
  3. 当它处理请求时,它有226 MB可用
    • 只要该请求不超过226 MB(+误差范围),请求就完成无错误
    • 如果它确实超过226 MB + margin,实例完成请求,记录'Exceeded soft private memory limit'错误,然后终止 - 现在返回步骤1
  4. 当该请求返回时,它所使用的任何内存都被释放 - 即.未使用的RAM回到226 MB
  5. 对于传递给实例的每个请求,无限期地重复步骤3-4

这就是我认为这是可行的,但考虑到我偶尔会穿过一个相当看到此错误广集请求处理的,现在我不那么肯定.我的问题是:

a)第4步会发生吗?

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

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

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

在答案/评论中,如果可能,请链接到gae文档.

[编辑]额外信息:我的应用程序被统一为threadsafe: false.如果这与答案有关,请说明它是什么.我计划threadsafe: true很快改变.

[编辑] 澄清:这个问题是关于gae对内存管理的预期行为.因此,虽然像"呼叫gc.collect()" 这样的建议可能是相关问题的部分解决方案,但它们并没有完全回答这个问题.直到我理解gae预计会如何表现为止,使用gc.collect()对我来说就像伏都教编程一样.

最后:如果我把这一切都倒退了然后我提前道歉 - 我真的找不到有用的信息,所以我大多猜测..

Ale*_*lli 5

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

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

一旦您将模块声明为threadsafe,一个实例可能会同时处理多个请求(取决于您max_concurrent_requestsautomatic_scaling模块.yaml配置文件部分的设置;默认值为 8)。因此,您的实例的 RAM 将需要是每个请求所需的倍数。

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

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

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


Rit*_*ave 2

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