Python 为什么mmap.move()会占满内存?

2024-04-20 14:51:25 发布

您现在位置:Python中文网/ 问答频道 /正文

编辑:使用Win10和python3.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个文件,每移动一个~30MB,内存就会充满~3GB。在

为什么移动的数据没有从内存中释放?在

我尝试过的方法没有效果:

  • 在函数末尾调用gc.collect()。在
  • 重写函数以将其分块移动。在

Tags: 数据方法函数内存编辑mapsizemove
1条回答
网友
1楼 · 发布于 2024-04-20 14:51:25

这似乎应该有效。我确实在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()
The munmap() system call deletes the mappings for the specified address range, and causes further references to addresses within the range to generate invalid memory references. The region is also automatically unmapped when the process is terminated. On the other hand, closing the file descriptor does not unmap the region.

(BSD文档类似。在这里,Windows可能与类Unix系统的行为有所不同,但您所看到的情况表明它们的工作方式相同。)

不幸的是,{cdmmap>和{cdmmap>的模块{cdmmap>和{cdmmap>都不调用^.4>和^ cdmmap>模块。作为解决方法,您可以使用ctypes模块。请参见this question以获取一个示例(它调用reboot,但相同的技术适用于所有C库函数)。或者,对于更好的方法,可以在中编写包装器。在

相关问题 更多 >