为什么我不需要释放这段内存?

6

我正在编写一个Python C扩展,在这里列出的示例中,有一段代码:

static PyObject * spam_system(PyObject *self, PyObject *args) {
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command)) return NULL;
    sts = system(command);
    return Py_BuildValue("i", sts);
}

根据使用PyArg_ParseTuple解析字符串的文档,“您不应提供字符串本身的存储;将现有字符串的指针存储到传递其地址的字符指针变量中。”那么Python如何知道“command”指向的内存何时可以释放?如何避免内存泄漏?

Python在哪里说它会自动释放内存?我认为你需要在使用完后手动释放。 - user395760
2
当它说“指向现有字符串的指针”时,我会认为PyArq_ParseTuple不会分配内存。虽然这不是一个安全的假设,我会检查文档。 - Thiago Cardoso
@delnan 我也是这么想的,但是当我尝试释放内存时,我得到了 *** glibc detected *** python: munmap_chunk(): invalid pointer: 0x0000000001ef16dc *** 的错误提示。 - amoffat
@Thiago 如果我一直运行spam_system,那么最终不会耗尽内存吗? - amoffat
是的,正如刚才回答的那样,没有额外的内存被分配。该函数返回一个指向先前分配的对象(args参数)的指针。 - Thiago Cardoso
1个回答

10

文档中对于 PyArg_ParseTuple 的 "s" 格式说明如下:

s (字符串或 Unicode) [const char *]
将 Python 字符串或 Unicode 对象转换为指向字符字符串的 C 指针。您不能为字符串本身提供存储空间;将现有字符串的指针存储到传递地址的字符指针变量中。

这意味着指针指向 Python 自己管理的内存。

如果您深入探索 Python 源代码(我使用的是版本 3.2),您会在 Python/getargs.c 中找到 PyArg_ParseTuple。如果您跟踪执行过程(如果您已经了解 C,则一个 Mark-I 眼球应该足够),您将到达 convertsimple,它处理一些简单的数据类型格式字符串(例如 "s")。然后看一下开关语句的 's' 分支,您将看到以下内容:

char **p = va_arg(*p_va, char **);
/* ... */
*p = PyBytes_AS_STRING(uarg);

稍微使用grep命令即可找到PyBytes_AS_STRING的定义:

#define PyBytes_AS_STRING(op) (assert(PyBytes_Check(op)), \
                                (((PyBytesObject *)(op))->ob_sval))
所以,这实际上只是将一个指针交给你指向Python对象内部的字段ob_sval,Python管理其内部对象的内存。因此,你不应该释放command字符串,因为它最终指向Python的一些内部数据,Python本身负责该内存。因此,在文档中发出了“不要碰”的警告。

谢谢@mu,我应该想到在源代码中寻找答案。 - amoffat
@Andrew: 我本来就怀疑会跟 PyBytes_AS_STRING 类似,我只是在验证我的猜测。无论如何,很高兴能提供帮助。 - mu is too short
Python 何时实际上释放内存?它是否知道我们正在函数调用中,一旦函数返回就可以释放内存? - Matthew Moisen
@MatthewMoisen 我猜测 PyBytesObject 有一个垃圾回收系统。 - mu is too short

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接