是否需要在Cython中显式删除动态分配的容器(如std :: vector)

时间:2017-01-23 01:27:26

标签: python c memory-management garbage-collection cython

许多Cython STL测试看起来像这样:

def simple_test(double x):
    """
    >>> simple_test(55)
    3
    """
    v = new vector[double]()
    try:
        v.push_back(1.0)
        v.push_back(x)
        from math import pi
        v.push_back(pi)
        return v.size()
    finally:
        del v

那里是否需要del语句,或者Python的/ Cython的引用计数是否适用于我们?

1 个答案:

答案 0 :(得分:1)

TL; DR

您需要del因为vector不是python类。

更长的答案

有许多因素使得pythons垃圾收集器无法收集该对象:

  • vector个实例没有reference-count属性,因为它们的类/结构不包含PyObject_HEAD。这是一个C(C ++)类,为什么会这样呢?

  • Python对象使用PyObject_GC_New使垃圾收集器知道其实例,并PyObject_GC_Del(或PyObject_GC_UnTrack)进行删除。但是vector使用new进行创建(在堆上),因此垃圾收集器根本不涉及 ,因此您需要一个明确的del(我认为) delete也应该有效,但我没有检查过)。

这也可以在源代码中看到(我使用ipythons %%cython,因此示例是可重现的):

%%cython --cplus

from libcpp.vector cimport vector

def simple_test(double x):
    v = new vector[double]()
    try:
        v.push_back(1.0)
        v.push_back(x)
        from math import pi
        v.push_back(pi)
        return v.size()
    finally:
        del v

.cpp文件中提供以下(极端)缩短的代码(通常此文件位于主目录的.ipython/cython文件夹中):

  /* "_cython_magic_9df9dbf5f4981f282eb46337245f3bb9.pyx":9
 *     3
 *     """
 *     v = new vector[double]()             # <<<<<<<<<<<<<<
 *     try:
 *         v.push_back(1.0)
 */
  try {
    __pyx_t_1 = new std::vector<double> ();
  } catch(...) {
    [...]
  }
  __pyx_v_v = __pyx_t_1;


  /* "_cython_magic_9df9dbf5f4981f282eb46337245f3bb9.pyx":17
 *         return v.size()
 *     finally:
 *         del v             # <<<<<<<<<<<<<<
 */
  [...]
      {
        delete __pyx_v_v;
      }

因此,如果没有del v,则不会有delete语句,您可能(可能)在代码中出现内存泄漏。

实践测试

%%cython --cplus

from libcpp.vector cimport vector

def simple_test(double x):
    v = new vector[double]()
    for _ in range(20000000):
        v.push_back(x)
    return v.size()
    # NO "del"!!!

import psutil

for _ in range(10):
    simple_test(10)
    print(psutil.virtual_memory().percent)

打印哪些:

47.5
49.4
51.2
53.1
55.1
57.0
58.9
60.8
62.8
65.0
66.9
68.9
70.6
72.5
74.5
76.4
78.4
80.3
82.2
83.6

因此,至少在我的计算机上,这导致内存使用量不断增加,而del的内存使用不会:

%%cython --cplus

from libcpp.vector cimport vector

def simple_test(double x):
    v = new vector[double]()
    try:
        for _ in range(20000000):
            v.push_back(x)
        return v.size()
    finally:
        del v         # this one has a del statement!!!

import psutil

for _ in range(20):
    simple_test(10)
    print(psutil.virtual_memory().percent)

结果:

47.4
47.4
47.4
47.4
47.4
47.4
47.4
47.4
47.2
47.2
47.2
47.2
47.2
47.2
47.2
47.2
47.2
47.2
47.2
47.3