2017-01-23 20 views
1

许多用Cython STL测试是这样的:是否需要显式删除动态分配容器(比如std ::向量)在用Cython

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的引用计数做为我们工作?

+0

垃圾收集器会自动清理它。 – Barmar

+1

@Barmar我不这么认为。除了任何理论上的考虑因素(因为它是一个C对象而不是Python对象,pythons gc如何知道何时以及如何收集它)只是运行该代码会在我的计算机上产生内存泄漏。 – MSeifert

回答

1

TL; DR

您需要del因为vector不是一个Python类。

再回应

有很多的因素,使得它不可能蟒蛇垃圾收集器收集对象:

  • vector实例没有因为他们的类的引用计数属性/ struct不包括PyObject_HEAD。这是一个C(C++)类,为什么呢?

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

这可以在源代码中被视为良好(I使用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文件夹在你的home目录):

/* "_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 
+0

'%% cython --cplus'我很好奇,这是你的设置文件的一部分?或者只是在这里发表评论? – MaxB

+1

@MaxB这是[ipython magic](https://ipython.org/ipython-doc/2/config/extensions/cythonmagic.html)。只需在ipython中加载'%load_ext cython'并且不需要安装文件('%% cython'就足够了)来测试cython代码:) – MSeifert

+0

'你需要del'没想到这个TBH(我'在Cython不好)。我问过的好事。这与我的'cython≈python'心智模式相矛盾。不得不''删除你的大部分对象是类C(C++通常受益于RAII而不是'new') – MaxB

相关问题