3

我有一些代码可以遍历数据库实体,并在任务中运行 - 见下文。

在应用程序引擎上我收到Exceeded soft private memory limit错误,并且确实检查memory_usage().current()确认了问题。有关日志记录语句的输出,请参见下文。似乎每次获取一批 foos 时,内存都会增加。

我的问题是:为什么内存没有被垃圾收集?我希望,在循环(分别为循环while和循环)的每次迭代中,for名称foos和变得不可访问),因此有资格进行垃圾收集,然后在内存紧张时进行垃圾收集。但显然它没有发生。foofoosfoo

from google.appengine.api.runtime import memory_usage

batch_size = 10
dict_of_results = {}
results = 0
cursor = None

while True:
  foos = models.Foo.all().filter('status =', 6)
  if cursor:
     foos.with_cursor(cursor)

  for foo in foos.run(batch_size = batch_size):

     logging.debug('on result #{} used memory of {}'.format(results, memory_usage().current()))
     results +=1

     bar  = some_module.get_bar(foo)

     if bar:
        try:
           dict_of_results[bar.baz] += 1
        except KeyError:
           dict_of_results[bar.baz] = 1


     if results >= batch_size:
        cursor = foos.cursor()
        break

  else:
     break   

在 some_module.py

def get_bar(foo):

  for bar in foo.bars:
    if bar.status == 10:
       return bar

  return None  

logging.debug 的输出(缩短)

on result #1 used memory of 43
on result #2 used memory of 43
.....
on result #20 used memory of 43
on result #21 used memory of 49
.....
on result #32 used memory of 49
on result #33 used memory of 54
.....
on result #44 used memory of 54
on result #45 used memory of 59
.....
on result #55 used memory of 59
.....
.....
.....

on result #597 used memory of 284.3
Exceeded soft private memory limit of 256 MB with 313 MB after servicing 1 requests total
4

2 回答 2

3

看起来您的批处理解决方案与 db 的批处理冲突,导致大量额外的批处理出现。

当您运行时query.run(batch_size=batch_size),db 将运行查询,直到完成整个限制。当您到达批次的末尾时,db 将抓取下一批。但是,在 db 执行此操作后,您立即退出循环并重新开始。这意味着批次 1 -> n 都将在内存中存在两次。一次用于最后一个查询获取,一次用于您的下一个查询获取。

如果您想遍历所有实体,只需让 db 处理批处理:

foos = models.Foo.all().filter('status =', 6)
for foo in foos.run(batch_size = batch_size):
  results +=1
  bar  = some_module.get_bar(foo)
  if bar:
    try:
      dict_of_results[bar.baz] += 1
    except KeyError:
      dict_of_results[bar.baz] = 1

或者,如果您想自己处理批处理,请确保 db 不进行任何批处理:

while True:
  foo_query = models.Foo.all().filter('status =', 6)
  if cursor:
    foo_query.with_cursor(cursor)
  foos = foo_query.fetch(limit=batch_size)
  if not foos:
    break

  cursor = foos.cursor()
于 2015-10-01T17:43:43.203 回答
0

可能看错了方向。

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

于 2015-10-01T08:52:29.293 回答