【C语言调用Python】Py_Finalize() 时报 GC 崩溃错误。
Py_Finalize() 时报 GC 崩溃错误。
记一次有趣的报错随笔。
报错现场
在使用如下的报错代码时,在释放阶段调用Py_Finalize()
,报如下Assert崩溃。
原因
结论
在调用函数逻辑里的Exit0中,对变量pModuleDict
和pClass
进行了手动释放,引用计数-1(宏KLP_RELEASE
),这两个变量是借用的引用变量,不需要修改引用计数,直接交给Py_Finalize()
能够自动回收。
修正后的代码只需要删除KLP_RELEASE(pModuleDict);
和KLP_RELEASE(pClass);
即可。
如果其他代码对这两个变量进行了引用计数的增加,才需要手动减少,不然不需要手动释放。
参考:https://stackoverflow.com/questions/6757741/py-finalize-crashes-after-error-in-python
猜想(暴论)
CPython中的Get函数返回的变量都是借用的,不会实际增加引用计数。
报错代码
#define KLP_RELEASE(p) { if (p) { Py_DecRef(p); (p) = NULL; } }
// 调用函数
KL_DLLEXPORT KLcBool KLpePfEyeLaunch()
{
KLcBool klBool = KL_FALSE;
PPYOBJECT pModule = NULL;
PPYOBJECT pModuleDict = NULL;
PPYOBJECT pClass = NULL;
PPYOBJECT pClassConstruct = NULL;
PPYOBJECT pClassIns = NULL;
PPYOBJECT pClassRet = NULL;
pModule = PyImport_ImportModule("WizardUltra");
KLP_PROCESS_ERROR(pModule);
pModuleDict = PyModule_GetDict(pModule);
KLP_PROCESS_ERROR(pModuleDict);
pClass = PyDict_GetItemString(pModuleDict, "CwuKL25COM");
KLP_PROCESS_ERROR(pClass);
pClassConstruct = PyInstanceMethod_New(pClass);
KLP_PROCESS_ERROR(pClassConstruct);
pClassIns = PyObject_CallObject(pClassConstruct, NULL);
KLP_PROCESS_ERROR(pClassIns);
pClassRet = PyObject_CallMethod(pClassIns, "getValue", NULL);
KLP_PROCESS_ERROR(pClassRet);
PyArg_Parse(pClassRet, "i", &klBool);
KLP_PROCESS_ERROR(klBool);
KLLOG(KLOG_INFO, L"PfEye launch ret: %d", klBool);
klBool = KL_TRUE;
Exit0:
KLP_RELEASE(pModule);
KLP_RELEASE(pModuleDict);
KLP_RELEASE(pClass);
KLP_RELEASE(pClassConstruct);
KLP_RELEASE(pClassIns);
KLP_RELEASE(pClassRet);
return klBool;
}
// 释放函数
KL_DLLEXPORT KLcBool KLpUninitPy3(KLPPY3OBJECTLINKCONTAINERDATA_PTR pPy3ObjectData)
{
KLcBool klBool = KL_FALSE;
klBool = Py_IsInitialized();
if (KL_TRUE == klBool)
{
Py_Finalize();
}
klBool = KL_TRUE;
Exit0:
return klBool;
}