重复的os.path.isdir调用中出现大量内存泄漏?

时间:2012-09-28 23:58:33

标签: python memory-leaks python-2.7 system-calls

我一直在编写与扫描目录有关的内容,并在调用os.path.isdir时注意到严重的内存泄漏,所以我尝试了以下代码段:

def func():
    if not os.path.isdir('D:\Downloads'):
        return False
while True:
    func()

在几秒钟内,Python进程达到了100MB RAM。

我正在试图弄清楚发生了什么。只有当路径确实是一个有效的目录路径(意味着没有执行'return False')时,似乎巨大的内存泄漏才有效。 另外,看看相关调用中会发生什么很有趣,比如os.path.isfile。

思想?

修改 我想我正在做点什么。 虽然isfile和isdir是在genericpath模块中实现的,但在Windows系统上 - isdir是从内置模块导入的。 所以我不得不下载2.7.3源码(我早就应该做了......)。

经过一番搜索后,我在 \ Modules \ posixmodule.c 中找到了 posix__isdir 函数,我假设这是从nt导入的'isdir'函数。

这部分功能(和评论)引起了我的注意:

if (PyArg_ParseTuple(args, "U|:_isdir", &po)) {
        Py_UNICODE *wpath = PyUnicode_AS_UNICODE(po);

        attributes = GetFileAttributesW(wpath);
        if (attributes == INVALID_FILE_ATTRIBUTES)
            Py_RETURN_FALSE;
        goto check;
    }
    /* Drop the argument parsing error as narrow strings
       are also valid. */
    PyErr_Clear();

似乎这一切都归结为Unicode / ASCII处理错误。

我刚刚尝试使用unicode中的路径参数上面的代码片段(即u'D:\ Downloads') - 没有任何内存泄漏。哈哈。

1 个答案:

答案 0 :(得分:8)

根本原因是无法在非Unicode路径中调用PyMem_Free变量上的path

    if (!PyArg_ParseTuple(args, "et:_isdir",
                          Py_FileSystemDefaultEncoding, &path))
        return NULL;

    attributes = GetFileAttributesA(path);
    if (attributes == INVALID_FILE_ATTRIBUTES)
        Py_RETURN_FALSE;

check:
    if (attributes & FILE_ATTRIBUTE_DIRECTORY)
        Py_RETURN_TRUE;
    else
        Py_RETURN_FALSE;

根据PyArg_ParseTuple上的文档:

  
      
  • et:与es ...
  • 相同   
  • esPyArg_ParseTuple()将分配所需大小的缓冲区,将编码数据复制到此缓冲区并调整* buffer以引用新分配的存储。 调用者负责在使用后调用PyMem_Free()释放分配的缓冲区
  •   

这是Python标准库中的一个错误(通过直接使用字节对象在Python 3中修复);在http://bugs.python.org提交错误报告。