2017-05-14 18 views
0

저는 실제로 C++로 게임을 개발 중이며 스크립트 langage로 AI를 수행하려고합니다. 그렇게하기 위해 Python/Python/C API를 선택했다. AI가 실제로 작동하지만 큰 문제가 있습니다. 프로그램에서 valgrind를 실행하면 많은 오류와 메모리 누수가 발생합니다. 그래서, 내 코드 또는 API 때문에 이런 일이 발생했는지 알 수 있습니까?Python/C API로 Valgrind 오류 및 메모리 누수가 발생했습니다.

IA::IA() 
{ 
    setenv("PYTHONPATH",".",1); 
    Py_Initialize(); 
    PyRun_SimpleString("import sys"); 
    pName = PyBytes_FromString((char*)"Test"); 
    pModule = PyImport_Import(pName); 
    pDict = PyModule_GetDict(pModule); 
    pFunc = PyDict_GetItemString(pDict, "push_f"); 
} 

IA::~IA() 
{ 
    Py_DECREF(pValue); 
    Py_DECREF(pModule); 
    Py_DECREF(pName); 
    Py_Finalize(); 
} 

void IA::LaunchIA(float x, float y, float z) 
{ 
    PyObject *toSend; 

    toSend = Py_BuildValue("(OOO)", TlistMob, TlistPlayer, pDPosIA); 
    pResult = PyObject_CallObject(pFunc, toSend); 
    PyErr_Print(); 
    printf("return = %f\n", (float)PyInt_AsLong(pResult)); 

} 

내 (매우) 간단한 파이썬 코드 :

def push_f(MobList, PlayerList, pos): 
    return 0 

그리고 Valgrind의 오류 (X1000) : 여기

은 AI 내 수업을 요약 한 것입니다

==11602== Memcheck, a memory error detector 
==11602== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==11602== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info 
==11602== Command: ./a.out 
==11602== 
==11602== Invalid read of size 4 
==11602== at 0x4FCE173: PyObject_Free (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F02FC2: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4FBDE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F85BAD: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F872FF: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F88559: PyImport_ImportModuleLevel (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EFF697: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F4B1E2: PyObject_Call (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x5021446: PyEval_CallObjectWithKeywords (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EF45C5: PyEval_EvalFrameEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x502201B: PyEval_EvalCodeEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EF0B88: PyEval_EvalCode (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== Address 0x693c020 is 2,560 bytes inside a block of size 2,731 free'd 
==11602== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==11602== by 0x4F81D28: PyMarshal_ReadLastObjectFromFile (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F85A22: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F872FF: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F88559: PyImport_ImportModuleLevel (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EFF697: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F4B1E2: PyObject_Call (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x5021446: PyEval_CallObjectWithKeywords (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EF45C5: PyEval_EvalFrameEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x502201B: PyEval_EvalCodeEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EF0B88: PyEval_EvalCode (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F851B3: PyImport_ExecCodeModuleEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== Block was alloc'd at 
==11602== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==11602== by 0x4F81CDF: PyMarshal_ReadLastObjectFromFile (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F85A22: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F872FF: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F88559: PyImport_ImportModuleLevel (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EFF697: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F4B1E2: PyObject_Call (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x5021446: PyEval_CallObjectWithKeywords (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EF45C5: PyEval_EvalFrameEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x502201B: PyEval_EvalCodeEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4EF0B88: PyEval_EvalCode (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== by 0x4F851B3: PyImport_ExecCodeModuleEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0) 
==11602== 
==11602== 
==11602== HEAP SUMMARY: 
==11602==  in use at exit: 491,741 bytes in 204 blocks 
==11602== total heap usage: 3,301 allocs, 3,097 frees, 3,567,424 bytes allocated 
==11602== 
==11602== LEAK SUMMARY: 
==11602== definitely lost: 0 bytes in 0 blocks 
==11602== indirectly lost: 0 bytes in 0 blocks 
==11602==  possibly lost: 1,072 bytes in 2 blocks 
==11602== still reachable: 490,669 bytes in 202 blocks 
==11602==   suppressed: 0 bytes in 0 blocks 
==11602== Rerun with --leak-check=full to see details of leaked memory 
==11602== 
==11602== For counts of detected and suppressed errors, rerun with: -v 
==11602== Use --track-origins=yes to see where uninitialised values come from 
==11602== ERROR SUMMARY: 497 errors from 25 contexts (suppressed: 0 from 0) 

필자가 알고 자하는 것은 하나의 IA 객체 만 생성한다는 것입니다.

내가 잘못 했나요? 아니면 그냥 API입니까?

사전에

감사합니다 (이것은 내가 내 C++ 실행하지 파이썬에 Valgrind의 실행되기 때문에 중복, 내 C++ 스크립트를 실행하지 않음)!

+0

[valgrind를 Python C++ 확장과 함께 사용하는 방법은 무엇입니까?] (http://stackoverflow.com/questions/3982036/how-can-i-use-valgrind-with-python-c-extensions) – DavidW

+0

나는 복제본이 맞으면 100 % 확신 할 수 없으므로 원한다면 동의하지 말고 많은 오류를 무시하는 데 도움이 될 수 있습니다. 또한 : (대부분의) 파이썬 호출에서 반환 값을 NULL로 체크해야합니다. 그것이 오류가 발생했는지를 알 수있는 방법입니다. – DavidW

+0

고마워요, 그랬지만 여전히 오류가 남아 있습니다 : "크기 8의 초기화되지 않은 값의 사용 == 10564 == 0x4FCE194 : PyObject_Free (/usr/lib/x86_64-linux-gnu/libpython2.7.so. 1.0) ". 나는 C++에서 파이썬 함수의 모든 반환을 검사했고 오류 메시지가 나타나지 않았다. –

답변

0

처음에는 this을 중복으로 제안했습니다. 필자는 그런 생각은 더 이상하지 않지만 Python 프로그램의 Valgrind 출력에서 ​​오탐을 제거하는 데 유용한 조언을 제공합니다.

프로그램에 특정 문제의 번호가 넘어 것을 :

  • 오류 검사 - 파이썬 C API는 일반적으로 오류를 나타 내기 위해 NULL 반환 값을 사용합니다. 이 코드 오류 검사를 작성 분명히 여러 가지 방법이 있지만, 나는

    IA::IA() : 
    pModule(NULL), pDict(NULL), pFunc(NULL), pName(NULL) // initially null initialize everything 
    { 
        setenv("PYTHONPATH",".",1); 
        Py_Initialize(); 
    
        // I don't think you actually use this line, so maybe remove it 
        if (PyRun_SimpleString("import sys") == -1) goto error; 
    
        pName = PyBytes_FromString((char*)"Test"); 
        if (!pName) goto error; 
        pModule = PyImport_Import(pName); 
        if (!pModule) goto error; 
        pDict = PyModule_GetDict(pModule); 
        if (!pDict) goto error; 
        pFunc = PyDict_GetItemString(pDict, "push_f"); 
        if (!pFunc) goto error; 
    
        return; // completed OK 
    
        error: 
        Py_XDECREF(pName); // XDECREF is OK with NULL... 
        Py_XDECREF(pModule); 
        Py_XDECREF(pDict); 
        Py_XDECREF(pFunc); 
        PyErr_Print(); 
        throw std::runtime_error(""); // ??? - possibly get and use the error string 
          // see https://stackoverflow.com/a/1418703/4657412 
    } 
    

    처럼 뭔가를 갈 유혹 것 내가 알고 사람들이 goto 의심하지만,이 경우는 점프의 합리적 깨끗한 방법이야 오류 처리 블록 원한다면 다르게 구조화 할 수 있습니다.

  • 소멸자가 메모리 누수처럼 보이는 pFunc을 지정하지 않습니다.

  • IA::LaunchIA 마찬가지로 작동 오류 검사가 부족합니다.

  • IA::LaunchIA 결코 toSend, pResult, TlistMob, TlistPlayer, pDPosIA을 decrefs 없습니다. 이 중 일부는 표시되는 코드의 불완전성에 관련되어 있지만, 그렇지 않으면 메모리가 누출됩니다.

  • 오류를 확인하지 않고 PyErr_Print()으로 전화하십시오. 설명서 내용 :

    오류 표시기가 설정된 경우에만이 기능을 호출하십시오. (그렇지 않으면 치명적인 오류가 발생합니다!)

    이것이 가장 큰 문제인 것으로 생각됩니다.


사람들은 내가 볼 수있는 모든 문제입니다. 최소한의 완전한 예제가 없다면 실제로보고있는 것을 확인하는 것은 불가능합니다. C++을 사용한다면 PyObject*에 대한 객체 지향적 인 래퍼를 사용하거나 참조하는 것이 좋습니다. 부스트 파이썬에는 참조 계산에 대해 걱정할 필요가 없습니다.

+0

큰 답변/자습서를위한 Thaaaaaanks !!! 그게 효과가! –