zmb*_*mbq 6 python memory-leaks tar python-3.x objgraph
我有一个Python实用程序,它遍历tar.xz文件并处理每个单独的文件.这是一个15MB的压缩文件,包含740MB的未压缩数据.
在内存非常有限的一台特定服务器上,程序因内存不足而崩溃.我使用objgraph来查看创建了哪些对象.事实证明,TarInfo实例没有被释放.主循环类似于:
with tarfile.open(...) as tar:
while True:
next = tar.next()
stream = tar.extractfile(next)
process_stream()
iter+=1
if not iter%1000:
objgraph.show_growth(limit=10)
Run Code Online (Sandbox Code Playgroud)
输出非常一致:
TarInfo 2040 +1000
TarInfo 3040 +1000
TarInfo 4040 +1000
TarInfo 5040 +1000
TarInfo 6040 +1000
TarInfo 7040 +1000
TarInfo 8040 +1000
TarInfo 9040 +1000
TarInfo 10040 +1000
TarInfo 11040 +1000
TarInfo 12040 +1000
Run Code Online (Sandbox Code Playgroud)
这一直持续到所有30,000个文件都被处理完毕.
为了确保,我已经注释掉了创建流并处理流的行.内存使用情况保持不变 - TarInfo实例泄露.
我正在使用Python 3.4.1,这种行为在Ubuntu,OS X和Windows上是一致的.
看起来这实际上是设计的.该TarFile对象维护TarInfo它在members属性中包含的所有对象的列表.每次调用时next,TarInfo它从存档中提取的对象都会添加到列表中:
def next(self):
"""Return the next member of the archive as a TarInfo object, when
TarFile is opened for reading. Return None if there is no more
available.
"""
self._check("ra")
if self.firstmember is not None:
m = self.firstmember
self.firstmember = None
return m
# Read the next block.
self.fileobj.seek(self.offset)
tarinfo = None
... <snip>
if tarinfo is not None:
self.members.append(tarinfo) # <-- the TarInfo instance is added to members
Run Code Online (Sandbox Code Playgroud)
members当您提取更多项目时,该列表将继续增长.这样可以使用getmembers和getmember方法,但这只会对您的用例造成麻烦.似乎最好的解决方法是在members迭代时继续清除属性(如此处所示):
with tarfile.open(...) as tar:
while True:
next = tar.next()
stream = tar.extractfile(next)
process_stream()
iter+=1
tar.members = [] # Clear members list
if not iter%1000:
objgraph.show_growth(limit=10)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
373 次 |
| 最近记录: |