Python单调增加的内存使用(泄漏?)
我在用一段简单的代码,发现内存使用量一直在增加。我在用一个小模块把东西存到磁盘上。我注意到这个问题出现在unicode字符串上,而不是整数上,我是不是做错了什么?
当我执行:
>>> from utils.diskfifo import DiskFifo
>>> df=DiskFifo()
>>> for i in xrange(1000000000):
... df.append(i)
内存消耗是稳定的
但是当我执行:
>>> while True:
... a={'key': u'value', 'key2': u'value2'}
... df.append(a)
内存使用量就飙升了。有没有什么建议?下面是这个模块的代码...
import tempfile
import cPickle
class DiskFifo:
def __init__(self):
self.fd = tempfile.TemporaryFile()
self.wpos = 0
self.rpos = 0
self.pickler = cPickle.Pickler(self.fd)
self.unpickler = cPickle.Unpickler(self.fd)
self.size = 0
def __len__(self):
return self.size
def extend(self, sequence):
map(self.append, sequence)
def append(self, x):
self.fd.seek(self.wpos)
self.pickler.dump(x)
self.wpos = self.fd.tell()
self.size = self.size + 1
def next(self):
try:
self.fd.seek(self.rpos)
x = self.unpickler.load()
self.rpos = self.fd.tell()
return x
except EOFError:
raise StopIteration
def __iter__(self):
self.rpos = 0
return self
2 个回答
0
为了补充combatdave@的回答:
我直接绕过了pickle中糟糕的内存缓存,因为在读取时清除缓存似乎是不可能的,这导致了明显的内存泄漏。pickle的流式处理似乎是为了读取和写入中等大小的文件设计的,而不是为了处理无限的数据流。
所以我就用了以下这些简单的工具函数:
def framed_pickle_write(obj, stream):
serial_obj = pickle.dumps(obj)
length = struct.pack('>I', len(serial_obj))
stream.write(length)
stream.write(serial_obj)
def framed_pickle_read(stream):
data = stream.read(4)
length, = struct.unpack('>I', data)
serial_obj = stream.read(length)
return pickle.loads(serial_obj)
15
pickler模块会把它见过的所有对象都存储在一个叫做“备忘录”的地方,这样就不需要重复处理同样的东西。如果你想跳过这个步骤(也就是说,不想在你的pickler对象中保存对这些对象的引用),你可以在保存之前先清空这个备忘录:
def append(self, x):
self.fd.seek(self.wpos)
self.pickler.clear_memo()
self.pickler.dump(x)
self.wpos = self.fd.tell()
self.size = self.size + 1
来源:http://docs.python.org/library/pickle.html#pickle.Pickler.clear_memo
补充说明:你实际上可以通过使用下面的追加函数,观察到备忘录的大小在你保存对象时是如何增加的:
def append(self, x):
self.fd.seek(self.wpos)
print len(self.pickler.memo)
self.pickler.dump(x)
self.wpos = self.fd.tell()
self.size = self.size + 1