Проверка утечек памяти в C++ со встроенным Python

Я пишу код C++, в который встроен модуль Python. Я импортирую модуль только один раз в начале; затем код C++ неоднократно вызывает из него одну функцию. Для этого я использовал следующий синтаксис (здесь представлен минимальный рабочий пример, предполагая, что функция Python принимает два аргумента с плавающей запятой и возвращает значение с плавающей запятой):

int main() {
   
    // Initialise the Python interpreter
    Py_Initialize();

    PyObject *pFunc = NULL, *pModule = NULL;

    const char* module_name   = "mod_name";
    const char* function_name = "fun_name";

    // Importing module
    pModule = PyImport_ImportModule(module_name);

    // Sanity check on module pointer
    if (pModule == NULL) {
        PyErr_Print();
        std::cout << "ERROR importing module" << std::endl;
        std::exit(1);
    }

    // Import function from Python module 
    pFunc = PyObject_GetAttrString(pModule, function_name);
    if (pFunc == NULL) {
        Py_CLEAR(pModule);
        PyErr_Print();
        std::cout << "ERROR getting test function" << std::endl;
        std::exit(1);
    }

    // Free module pointer
    Py_CLEAR(pModule);


    double val1 = 1.5;
    double val2 = 2.5;

    for (int i = 0; i < 10; i++){
        
        // Specify inputs of the Python function that has to be called
        pArgs = PyTuple_Pack(2, PyFloat_FromDouble(val1), PyFloat_FromDouble(val2) );
 
         
        // Checking that the tuple packing was performed correctly
        if (pArgs == NULL) {
            PyErr_Print();
            std::cout << "ERROR packing arguments" << std::endl;
            std::exit(1);
        } 
        
   
        // Call the Python function and store the returned value in pValue
        pValue = PyObject_CallObject(pFunc, pArgs);

        // Checking that the function call was performed correctly
        if (pValue == NULL) {
            Py_CLEAR(pArgs);
            PyErr_Print();
            std::cout << "ERROR getting value from function" << std::endl;
            std::exit(1);
         }
    
        //SUCCESSFULLY COMPLETED PYTHON CALL
        double res= PyFloat_AsDouble(pValue);
    
        // Free all the allocated memory
        Py_CLEAR(pArgs);
        Py_CLEAR(pValue);
   
    } 

    // Free the shared pointer to python function
    Py_CLEAR(pFunc);
    Py_Finalize();
    return 0;
}

Я профилировал свой исполняемый файл C++ с помощью valgrind, чтобы проверить наличие утечек памяти. В то время как когда я изолирую разделы кода C++, все работает нормально, как только я запускаю полный код со встроенным разделом Python, я получаю утечки памяти. Ниже приведен пример отчета об убытках из исходного кода: отчет об убытках valgrind

Я знаю, что valgrind может давать странные результаты при взаимодействии с кодом Python, поэтому я обращаюсь сюда, чтобы узнать, есть ли какие-либо рекомендации по проверке утечек памяти при встраивании Python в C++.

Кроме того, это мой первый вопрос здесь, поэтому, если какая-либо полезная информация отсутствует, пожалуйста, не стесняйтесь спрашивать об этом! заранее спасибо


person Paolo Madonia    schedule 28.05.2021    source источник
comment
Отвечает ли это на ваш вопрос? Утечка памяти при встраивании python в мое приложение   -  person Frank    schedule 28.05.2021


Ответы (1)


Проблема, с которой вы столкнулись, заключается в том, что valgrind понимает распределения, выполняемые через malloc, но не понимает распределения на арене python. Поэтому, если на выделение malloc ссылаются только из распределения python, valgrind не уловит этого и будет считать выделение malloc утечкой.

Я рекомендую вам использовать https://github.com/vmware/chap, так как он может распознавать как виды выделений.

Запустите вашу программу без valgrind, но в какой-то момент, прежде чем ваша программа завершится, соберите живое ядро, либо используя gcore, либо запустив generate из gdb в точке останова.

Затем запустите главу и попробуйте следующее из подсказки главы:

count leaked

Если это показывает ненулевое значение, проверьте https://github.com/vmware/chap/blob/master/USERGUIDE.md для получения дополнительных советов по анализу утечки.

person Tim Boddy    schedule 28.05.2021
comment
старые версии Python должны были быть настроены специально, чтобы позволить valgrind понять распределение python. Это больше не требуется с последним python: см. выдержку из cpython/README.valgrind ОБНОВЛЕНИЕ: Python 3.6 теперь поддерживает переменную среды PYTHONMALLOC=malloc, которую можно использовать для принудительного использования распределителя malloc() библиотеки C. - person phd; 29.05.2021