【发布时间】:2018-05-06 00:25:46
【问题描述】:
我无法在 Python 中释放内存。情况基本上是这样的:我有一个大数据集分成 4 个文件。每个文件包含 5000 个形状为 (3072, 412) 的 numpy 数组的列表。我试图将每个数组的第 10 列到第 20 列提取到一个新列表中。
我想做的是顺序读取每个文件,提取我需要的数据,并在继续下一个之前释放我正在使用的内存。但是,删除对象,将其设置为 None 并将其设置为 0 然后调用 gc.collect() 似乎不起作用。这是我正在使用的代码的 sn-p:
num_files=4
start=10
end=20
fields = []
for j in range(num_files):
print("Working on file ", j)
source_filename = base_filename + str(j) + ".pkl"
print("Memory before: ", psutil.virtual_memory())
partial_db = joblib.load(source_filename)
print("GC tracking for partial_db is ",gc.is_tracked(partial_db))
print("Memory after loading partial_db:",psutil.virtual_memory())
for x in partial_db:
fields.append(x[:,start:end])
print("Memory after appending to fields: ",psutil.virtual_memory())
print("GC Counts before del: ", gc.get_count())
partial_db = None
print("GC Counts after del: ", gc.get_count())
gc.collect()
print("GC Counts after collection: ", gc.get_count())
print("Memory after freeing partial_db: ", psutil.virtual_memory())
这是几个文件后的输出:
Working on file 0
Memory before: svmem(total=67509161984, available=66177449984,percent=2.0, used=846712832, free=33569669120, active=27423051776, inactive=5678043136, buffers=22843392, cached=33069936640, shared=15945728)
GC tracking for partial_db is True
Memory after loading partial_db: svmem(total=67509161984, available=40785944576, percent=39.6, used=26238181376, free=8014237696, active=54070542336, inactive=4540620800, buffers=22892544, cached=33233850368, shared=15945728)
Memory after appending to fields: svmem(total=67509161984, available=40785944576, percent=39.6, used=26238181376, free=8014237696, active=54070542336, inactive=4540620800, buffers=22892544, cached=33233850368, shared=15945728)
GC Counts before del: (0, 7, 3)
GC Counts after del: (0, 7, 3)
GC Counts after collection: (0, 0, 0)
Memory after freeing partial_db: svmem(total=67509161984, available=40785944576, percent=39.6, used=26238181376, free=8014237696, active=54070542336, inactive=4540620800, buffers=22892544, cached=33233850368, shared=15945728)
Working on file 1
Memory before: svmem(total=67509161984, available=40785944576, percent=39.6, used=26238181376, free=8014237696, active=54070542336, inactive=4540620800, buffers=22892544, cached=33233850368, shared=15945728)
GC tracking for partial_db is True
Memory after loading partial_db: svmem(total=67509161984, available=15378006016, percent=77.2, used=51626561536, free=265465856, active=62507155456, inactive=3761905664, buffers=10330112, cached=15606804480, shared=15945728)
Memory after appending to fields: svmem(total=67509161984, available=15378006016, percent=77.2, used=51626561536, free=265465856, active=62507155456, inactive=3761905664, buffers=10330112, cached=15606804480, shared=15945728)
GC Counts before del: (0, 4, 2)
GC Counts after del: (0, 4, 2)
GC Counts after collection: (0, 0, 0)
Memory after freeing partial_db: svmem(total=67509161984, available=15378006016, percent=77.2, used=51626561536, free=265465856, active=62507155456, inactive=3761905664, buffers=10330112, cached=15606804480, shared=15945728)
如果我继续放手,它将耗尽所有内存并触发MemoryError 异常。
谁知道我可以做些什么来确保partial_db 使用的数据被释放?
【问题讨论】:
-
释放内存时,CPython 很少将其释放到操作系统。但它会重用它而不是分配更多。所以用这种方式跟踪内存使用很容易误导自己。在前几个步骤之后,每个步骤结束时的总数是否比附加到
fields使用的额外内存增加了很多? (另外,你真的会得到一个“MemoryError”还是你担心你会?) -
您好 Abarnert,感谢您的快速回复。额外的内存使用似乎完全来自 partial_db 分配,而不是来自字段;但我会尝试附加到字段以确保。事实上,我在过程中遇到了 MemoryError。
-
刚刚注意到一些事情:您正在将可能是巨大的 numpy 数组的一部分附加到字段中。那不是副本,它是父数组的视图。这就是为什么使用 numpy 进行切片如此快速且节省空间的原因,但这也意味着切片视图只要该父级还活着(在您的情况下是永远的),它就会使该父级保持活动状态。如果删除附加使问题消失,请尝试更改为
append(x[:,start:end].copy())。如果可行,这就是您的解决方案。 -
哦,当然。这台机器现在有点反应迟钝,但这听起来很有希望!我会告诉你它是否有效。
-
这是调试内存问题最有趣的事情——当你将机器送入交换地狱时,一切都需要很长时间,甚至只是为了杀死进程......
标签: python linux numpy memory-leaks garbage-collection