编辑:使用Win10和python 3.5
我有一个使用mmap从某个偏移量的文件中删除字节的函数:
def delete_bytes(fobj, offset, size):
fobj.seek(0, 2)
filesize = fobj.tell()
move_size = filesize - offset - size
fobj.flush()
file_map = mmap.mmap(fobj.fileno(), filesize)
file_map.move(offset, offset + size, move_size)
file_map.close()
fobj.truncate(filesize - size)
fobj.flush()
它运行速度非常快,但是当我在大量文件上运行时,内存很快就会填满,我的系统也没有响应。
经过一些实验,我发现move()方法是罪魁祸首,特别是移动的数据量(move_size)。
正在使用的内存量等于mmap.move()
移动的数据总量。
如果我有100个文件,每个文件大约移动30 MB,内存就会充满~3GB。
为什么移动的数据不是从内存中释放的?
我尝试的事情没有效果:
gc.collect()
。答案 0 :(得分:1)
这似乎应该工作。我确实在mmapmodule.c源代码#ifdef MS_WINDOWS
中找到了一个可疑位。具体来说,在完成解析参数的所有设置之后,代码会执行以下操作:
if (fileno != -1 && fileno != 0) {
/* Ensure that fileno is within the CRT's valid range */
if (_PyVerify_fd(fileno) == 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
fh = (HANDLE)_get_osfhandle(fileno);
if (fh==(HANDLE)-1) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
/* Win9x appears to need us seeked to zero */
lseek(fileno, 0, SEEK_SET);
}
将您的基础文件对象的偏移量从"文件末尾"到"开始文件"然后把它留在那里。这似乎应该不会破坏任何东西,但是在调用mmap.mmap
来映射文件之前,可能值得自己寻找启动文件。
(下面的所有内容都是错误的,但是因为有评论而留下来。)
通常,使用 mmap()
后,必须使用munmap()
撤消映射。简单地关闭文件描述符无效。 Linux documentation明确地将其调出:
munmap()
munmap()
系统调用将删除指定地址范围的映射,并导致进一步引用该范围内的地址以生成无效的内存引用。当进程终止时,该区域也会自动取消映射。另一方面,关闭文件描述符不会取消映射该区域。
(BSD文档类似.Windows在这里可能与类Unix系统的行为不同,但你所看到的表明它们的工作方式相同。)
不幸的是,Python的mmap模块不绑定 munmap
系统调用(也不mprotect
),至少从2.7.11和3.4开始。 4。作为解决方法,您可以使用ctypes
模块。有关示例,请参阅this question(它调用reboot
,但相同的技术适用于所有C库函数)。或者,对于更好的方法,您可以在cython中编写包装器。