2017-01-23 9 views
1

Многие STL тесты Cython выглядеть следующим образом:Требуется ли явно удалить динамически распределяемых контейнеры (например, станд :: вектор) в 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 заявления, необходимые там, или будет/подсчет ссылок Cython в Пайтона делать работа для нас?

+0

Сборщик мусора автоматически очистит его. – Barmar

+1

@ Бармар Я так не думаю. Помимо теоретических соображений (потому что это объект C, а не объект Python, как бы знать pythons gc, когда и как его собирать), просто запуск этого кода вызывает утечку памяти на моем компьютере. – MSeifert

ответ

1

TL; DR

Вам нужен del потому vector не класс питона.

Более длинный ответ

Есть много факторов, которые делают невозможным для питоны сборщика мусора, чтобы собрать этот объект:

  • vector экземпляры не имеют атрибут справочно-счет, потому что их класс/struct не включает 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 там Wo uld be no 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). Просто загрузите '% load_ext cython' в ipython и вам не нужен установочный файл (достаточно' %% cython') для проверки кода на языке cython :) – MSeifert

+0

'Вам нужен del' Не ожидал, что этот TBH (I ' плохо в Китоне). Хорошо, что я спросил. Это противоречит моей психической модели «cython ≈ python». Для 'del' большинство ваших объектов C-like (C++ обычно извлекает выгоду из RAII без' new') – MaxB