我想使用管理命令对马萨诸塞州的建筑物进行一次性分析。我已将令人反感的代码缩减为8行代码段,以演示我遇到的问题。这些评论仅说明了我为什么要这样做。我在空白命令中逐字运行下面的代码
zips = ZipCode.objects.filter(state='MA').order_by('id')
for zip in zips.iterator():
buildings = Building.objects.filter(boundary__within=zip.boundary)
important_buildings = []
for building in buildings.iterator():
# Some conditionals would go here
important_buildings.append(building)
# Several types of analysis would be done on important_buildings, here
important_buildings = None
当我运行此确切的代码时,我发现每次迭代外循环时内存使用量都稳定增加(我print('mem', process.memory_info().rss)
用来检查内存使用量)。
important_buildings
即使超出范围,列表似乎也在占用内存。如果我替换important_buildings.append(building)
为_ = building.pk
,它不再消耗太多内存,但是对于某些分析,我确实需要该列表。
所以,我的问题是:当Python超出范围时,如何强制Python释放Django模型列表?
编辑:我觉得堆栈溢出有一个陷阱22-如果我写太多细节,没有人愿意花时间阅读它(这成为不太适用的问题),但是如果我写得太少详细信息,我冒险忽略部分问题。无论如何,我非常感谢您的回答,并计划在本周末尝试尝试一些建议时,我终于有机会回到这个话题!
您没有提供有关模型的大小以及模型之间存在什么链接的太多信息,因此这里有一些想法:
默认情况下QuerySet.iterator()
会2000
在内存中加载元素(假设您使用的是django> = 2.0)。如果您的Building
模型包含大量信息,则可能会占用大量内存。您可以尝试将chunk_size
参数更改为更低的值。
您的Building
模型在实例之间是否存在链接,这些链接可能导致gc
找不到参考循环?您可以使用gc
调试功能来获取更多详细信息。
或短路上述想法,也许只是打电话del(important_buildings)
,并del(buildings)
随后gc.collect()
在每个环路力垃圾收集的结束?
变量的范围是函数,而不仅仅是for
循环,因此将代码分解为较小的函数可能会有所帮助。尽管请注意python垃圾收集器不会总是将内存返回给操作系统,但是如本答案所述,您可能需要采取更多残酷的措施才能查看rss
故障。
希望这可以帮助!
编辑:
为了帮助您了解哪些代码占用了内存以及占用了多少内存,可以使用tracemalloc模块,例如,使用建议的代码:
import linecache
import os
import tracemalloc
def display_top(snapshot, key_type='lineno', limit=10):
snapshot = snapshot.filter_traces((
tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
tracemalloc.Filter(False, "<unknown>"),
))
top_stats = snapshot.statistics(key_type)
print("Top %s lines" % limit)
for index, stat in enumerate(top_stats[:limit], 1):
frame = stat.traceback[0]
# replace "/path/to/module/file.py" with "module/file.py"
filename = os.sep.join(frame.filename.split(os.sep)[-2:])
print("#%s: %s:%s: %.1f KiB"
% (index, filename, frame.lineno, stat.size / 1024))
line = linecache.getline(frame.filename, frame.lineno).strip()
if line:
print(' %s' % line)
other = top_stats[limit:]
if other:
size = sum(stat.size for stat in other)
print("%s other: %.1f KiB" % (len(other), size / 1024))
total = sum(stat.size for stat in top_stats)
print("Total allocated size: %.1f KiB" % (total / 1024))
tracemalloc.start()
# ... run your code ...
snapshot = tracemalloc.take_snapshot()
display_top(snapshot)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句