【问题标题】:Why do I not need to free this memory?为什么我不需要释放这个内存?
【发布时间】:2011-04-09 17:25:06
【问题描述】:

我正在编写一个 Python C 扩展,在 here 列出的示例中,有一段 sn-p 代码:

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如何知道“命令”指向的内存何时可以被释放呢?怎么没有发生内存泄漏?

【问题讨论】:

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

标签: python c memory-leaks


【解决方案1】:

documentation 将“s”格式说明符告诉PyArg_ParseTuple

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

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

如果您深入研究 Python 源代码(我使用的是 3.2 版),您会在 Python/getargs.c 中找到 PyArg_ParseTuple。如果您跟踪执行(如果您已经知道 C,则标记-I 的眼球应该足够了)您将到达convertsimple,它处理一些简单的数据类型格式字符串(例如“s”)。然后看看开关的's' 分支,你会看到:

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

一点点 grepping 将产生PyBytes_AS_STRING 的定义:

#define PyBytes_AS_STRING(op) (assert(PyBytes_Check(op)), \
                                (((PyBytesObject *)(op))->ob_sval))

所以这一切实际上是在给你一个指向 Python 对象内的字段 ob_sval 的指针; Python 正在为其内部对象管理内存。

因此,您不应该释放您的 command 字符串,因为它最终指向 Python 的一些内部数据,而 Python 本身负责该内存。因此,文档中出现了“放手”警告。

【讨论】:

  • 谢谢@mu,我应该考虑挖掘源代码来弄明白
  • @Andrew:我怀疑它会归结为PyBytes_AS_STRING,我主要是在验证我的猜测。无论如何,很高兴能提供帮助。
  • Python 什么时候真正开始释放内存?它是否知道我们正在进行函数调用,一旦函数返回,它就可以释放内存?
  • @MatthewMoisen 我猜PyBytesObject 有一个垃圾收集系统。
猜你喜欢
  • 1970-01-01
  • 2016-11-06
  • 2014-08-05
  • 1970-01-01
  • 2013-08-02
  • 1970-01-01
  • 2011-12-22
  • 2017-09-14
  • 1970-01-01
相关资源
最近更新 更多