3

当我对大量小对象(只有几个短字符串和布尔属性的 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()在循环结束时调用 a (也是请求结束);它返回0,并没有帮助。

更新 2:我做了一些黑客攻击让 guppy 在 dev_appserver 上工作,这似乎表明,在gc.collect()循环结束后明确指出,大部分内存被 google.appengine.datastore.entity_pb 的 'dict 。财产'。

4

2 回答 2

2

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

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

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

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

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

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

查看 apptrace 之类的工具来帮助进行内存分析。

于 2015-08-06T12:03:18.030 回答
1

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

于 2015-09-02T15:34:40.957 回答