【问题标题】:Google App Engine DB Query Memory UsageGoogle App Engine 数据库查询内存使用情况
【发布时间】:2015-08-06 10:43:45
【问题描述】:

当我对一大组小对象(只有几个短字符串和布尔属性的 15k 对象)运行查询时,没有对这些对象做任何事情,我看到我的实例的内存使用量不断增加(增加 70Mb)。内存增加看起来与它曾经需要保留在内存中以用于查询的数据量不成比例。

我使用的循环如下:

cursor = None
while True:
  query = MyModel.all()
  if cursor:
    query.with_cursor(cursor)
  fetched = 0
  for result in query.run(batch_size = 500):
    fetched += 1

    # Do something with 'result' here. Actually leaving it empty for 
    # testing to be sure I don't retain anything myself

    if fetched == 500:
      cursor = query.cursor()
      break
  else:
    break

为确保这不是由于 appstats,我致电 appstats.recording.dont_record() 不记录任何统计信息。

有人知道会发生什么吗?或者关于如何调试/分析这个的任何指针?

更新 1:我在生产代码上打开了gc.set_debug(gc.DEBUG_STATS),我看到垃圾收集器被定期调用,所以它正在尝试收集垃圾。当我在循环结束时(也是请求结束)调用gc.collect();它返回0,但没有帮助。

更新 2:我做了一些 hack,让 guppy 在 dev_appserver 上工作,这似乎表明,在循环结束时明确的 gc.collect() 之后,大部分内存是由“google.appengine.datastore.entity_pb.Property 的字典”使用。

【问题讨论】:

    标签: python google-app-engine google-cloud-datastore google-app-engine-python


    【解决方案1】:

    每个模型实体都有一些开销。

    您的查询返回对象作为初学者的 Protobufs。

    因此,您将为结果集生成一系列批处理的 protobuf。

    然后它被解码。每个解码的实体包括属性名称以及每个实体的数据。您有 15K 实体。例如,您的属性名称有多大。

    因此,您在内存中至少有两个不同形式的结果集副本(可能更多),不包括您对模型类实例所做的任何其他事情。

    您的代码/循环没有机会进行垃圾收集,这可能/将在以后发生。

    查看 apptrace 等工具来帮助进行内存分析。

    【讨论】:

    • 我猜我有大约 500 个字符用于属性名称 + 值的组合,所以假设为 1k。将所有内容保存在内存中确实会给我大约 15 兆,所以几次确实会加起来 60 兆。但是为什么它需要把它全部保存在内存中呢?您能否详细说明如何判断该循环中没有垃圾收集机会?我可以在循环中或循环之后使用gc.collect() 强制进行垃圾收集吗? (我试过前者,没有任何效果,所以这一定意味着我不明白为什么数据不可收集)。
    • 另外,我尝试了 apptrace,但这在最近的 dev_appserver 设置中似乎不再有效。
    • 我怀疑 gc.collect 在请求完成之前会做任何真正有价值的事情。在完成请求之前尝试将其称为最后一件事。我会建议两件事。 1. 远离 db 和 ndb,那里有许多效率。 2. 为什么要遍历所有 15K 实体 - 重新检查您要实现的目标。
    【解决方案2】:

    我已将此情况报告给应用引擎团队,他们似乎确认这实际上是一个问题(怀疑与游标的处理有关)。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    • 2015-12-22
    • 2011-08-16
    相关资源
    最近更新 更多