【问题标题】:Are there any Python reference counting/garbage collection gotchas when dealing with C code?处理 C 代码时是否有任何 Python 引用计数/垃圾收集陷阱?
【发布时间】:2010-05-29 13:13:58
【问题描述】:

纯粹为了它,我决定创建一个Scheme binding to libpython,以便您可以将 Python 嵌入到 Scheme 程序中。我已经能够调用 Python 的 C API,但我还没有真正考虑过内存管理。

mzscheme 的 FFI 的工作方式是我可以调用一个函数,如果该函数返回一个指向 PyObject 的指针,那么我可以让它自动增加引用计数。然后,我可以注册一个终结器,它会在 Scheme 对象被垃圾回收时减少引用计数。我查看了documentation for reference counting,乍一看并没有发现任何问题(尽管在某些情况下它可能不是最佳的)。有什么我遗漏的问题吗?

另外,我无法确定cyclic garbage collector documentation 的正面或反面。这里我需要记住什么?特别是,我如何让 Python 知道我引用了某些东西,这样它就不会在我仍在使用它时收集它?

【问题讨论】:

    标签: python garbage-collection scheme reference-counting python-c-api


    【解决方案1】:

    您指向http://docs.python.org/extending/extending.html#reference-counts 的链接是正确的地方。文档的扩展和嵌入以及 Python/C API 部分将解释如何使用 C API。

    引用计数是使用 C API 的烦人部分之一。主要问题是保持一切正常:根据您调用的 API 函数,您可能拥有也可能不拥有对所获得对象的引用。请注意了解您是拥有它(因此不能忘记 DECREF 或将其交给会窃取它的东西)还是借用它(并且必须 INCREF 以保留它并可能在您的函数期间使用它)。涉及此问题的最常见错误是 1) 错误地记住您是否拥有由特定函数返回的引用,以及 2) 认为您可以安全地借用引用的时间比实际时间长。

    您不必为循环垃圾收集器做任何特别的事情。它只是用来修补引用计数中的缺陷,不需要直接访问。

    【讨论】:

    • 所以...Python 使用引用计数 循环结构的垃圾收集器?这是一个相当大的缺陷。设计类。无论如何,如果参与 python 端循环的任何值都暴露给方案,这听起来会让 Jason 的事情变得更加“有趣”。
    • @Jason,只有 INCREF 借用引用。一些函数返回已被 INCREF 的 new 引用。对它们进行 INCREF 会导致内存泄漏。
    • @Eli,在 CPython 中杀死对象的主要策略是引用计数。由于引用计数不会在其他情况下无法访问的引用循环上进行,因此它增加了一个(可选,默认情况下)循环垃圾收集器。这种增强对于防止任何允许任意引用的引用计数系统中的内存泄漏是必要的。这只是一个设计缺陷,因为引用计数是一个设计缺陷(当然,有些人会声称)。
    • @Jason,不,这就是问题所在!有时你借用一个引用(并且需要 INCREF 来拥有对对象的引用),有时你通过调用函数窃取引用并已经拥有它;在这种情况下,INCREFing 可能会导致内存泄漏。同样,何时以及是否使用 DECREF 取决于某些函数是否窃取了您的引用,这会发生。 不同的函数提供或借出它们返回的引用并窃取或借用它们收到的引用。记住你正在使用的函数是做什么的,这就是为什么这可能是陷阱的来源。
    • @Eli,你没有对我说清楚;我以为您特别声称使用循环查找器增加引用计数是一个设计问题。你是否喜欢反驳是一个更大的问题,而且更多的是宗教问题而不是技术问题。
    【解决方案2】:

    我所知道的关于引用计数和 C API 的最大问题是 __del__。当你有一个借用的引用时,你认为你可以不用INCREF'ing就可以逃脱,因为你在使用那个引用时没有放弃GIL。但是,如果您最终删除了一个对象(例如,通过从列表中删除它),您可能会触发 __del__ 调用,这可能会删除您从脚下借用的引用。非常棘手。

    如果您在获得所有借用的引用后立即 INCREF(然后是 DECREF),那么应该没有任何问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 1970-01-01
      • 2011-03-29
      • 1970-01-01
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多