当我对一大组小对象(只有少量短字符串和布尔属性的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 :我做了一些黑客攻击,让guppy在dev_appserver上工作,这似乎指出,在循环结束时显式gc.collect()
后,大多数记忆是由'google.appengine.datastore.entity_pb.Property'的字典所消耗的。
答案 0 :(得分:2)
每个模型实体都有一些头脑。
您查询将对象作为初学者的Protobuf返回。
因此,您将为结果集添加一系列批处理的原型。
然后解码。每个解码的实体包括属性名称以及每个实体的数据。你有15K实体。例如,你的财产名称有多大。
因此,您在内存中至少有两个结果集副本(可能更多),不包括您对模型类实例所做的任何其他操作。
您的代码/循环没有机会进行垃圾收集,而且可以/稍后发生。
查看apptrace等工具来帮助进行内存分析。
答案 1 :(得分:1)
我已经向应用引擎团队报告了这一点,他们似乎确认这实际上是一个问题(怀疑是处理游标)。