Потенциальная утечка памяти при преобразовании широкого символа в строку Python

У меня есть следующий код в cython в файле pyx, который преобразует wchar_t * в строку python (юникод)

// Весь код ниже — это Python 2.7.4

cdef wc_to_pystr(wchar_t *buf):
    if buf == NULL:
        return None
    cdef size_t buflen
    buflen = wcslen(buf)
    cdef PyObject *p = PyUnicode_FromWideChar(buf, buflen)
    return <unicode>p

Я вызвал эту функцию в цикле следующим образом:

cdef wchar_t* buf = <wchar_t*>calloc(100, sizeof(wchar_t))
# ... copy some wide string to buf

for n in range(30000):
    u = wc_to_pystr(buf) #<== behaves as if its a memory leak

free(buf)

Я проверил это в Windows, и заметил, что память (как видно из диспетчера задач) продолжает увеличиваться, и поэтому я подозреваю, что здесь может быть утечка памяти.

Это удивительно, потому что:

  1. Насколько я понимаю, API PyUnicode_FromWideChar() копирует предоставленный буфер.
  2. Каждый раз, когда переменной 'u' присваивается другое значение, предыдущее значение должно быть освобождено.
  3. Поскольку исходный буфер ('buf') остается как есть и освобождается только после завершения цикла, я ожидал, что память после определенного момента вообще не должна увеличиваться.

Есть идеи, где я ошибаюсь? Есть ли лучший способ реализовать Wide Char для объекта unicode python?


person bitflood    schedule 07.12.2014    source источник
comment
не могли бы вы попробовать добавить del u в цикл for и снова проверить, продолжает ли увеличиваться память?   -  person gg349    schedule 07.12.2014
comment
@GiulioGhirardo, я пытался, как вы сказали, и память продолжает увеличиваться. На данный момент я не уверен, является ли это настоящей утечкой памяти или GC Python немного ленив, собирая мусор   -  person bitflood    schedule 08.12.2014


Ответы (1)



Решено! Решение:

(Примечание. Решение относится к фрагменту моего кода, которого изначально не было в вопросе. Я понятия не имел, когда публиковал, что он будет содержать ключ для решения этой проблемы. Извините тех, кто задумал решить...)

В файле cython pyx я объявил API python, например:

PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size)

Я проверил документы по адресу https://github.com. /cython/cython/blob/master/Cython/Includes/cpython/init.pxd

Я объявил возвращаемый тип как PyObject*, и, следовательно, была создана дополнительная ссылка, которую я не разыгрывал явно. Решение состояло в том, чтобы изменить тип возвращаемого значения в подписи, например:

object PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size)

В соответствии с документами добавление «объекта» в качестве типа возвращаемого значения не увеличивает количество ссылок и, следовательно, в цикле for память освобождается правильно. Модифицированный wc_to_pystr выглядит так:

cdef wc_to_pystr(wchar_t *buf):
    if buf == NULL:
        return None
    cdef size_t buflen
    buflen = wcslen(buf)
    p = PyUnicode_FromWideChar(buf, buflen)
    return p
person bitflood    schedule 08.12.2014