Python C API调用sys.getsizeof()出现段错误,请求排查问题
问题分析与修正方案
核心错误点
错误使用
PyModule_New导入模块PyModule_New是用来创建全新的空模块对象,而非导入Python已有的sys模块。你用这个函数得到的sys对象根本没有getsizeof方法,后续调用PyObject_CallMethodObjArgs会返回NULL,直接访问这个空指针就会触发段错误。正确导入现有模块应该用PyImport_ImportModule("sys")。冗余的引用计数操作
传入的obj参数在调用函数时应该已经持有合法的引用计数,额外执行Py_INCREF(obj)后又在结尾Py_DECREF(obj),会导致引用计数多减一次,可能引发对象提前释放或内存错误,直接去掉这两个操作即可。未检查API调用的返回值
导入模块、获取方法、调用方法等步骤都可能失败返回NULL,你没有做任何错误检查就直接使用返回值,空指针访问必然触发段错误。冗余的字符串对象创建
Py_BuildValue("s", "getsizeof")可以用更简洁的PyObject_GetAttrString替代,直接从sys模块获取getsizeof方法,省去手动创建字符串对象的步骤。
修正后的代码
// Returns in bytes the size of obj in memory (emulates sys.getsizeof(obj)) size_t getSizeOf(PyObject* obj) { // 检查输入对象合法性 if (!obj) { return 0; } // 正确导入sys模块 PyObject* sys_module = PyImport_ImportModule("sys"); if (!sys_module) { PyErr_Print(); return 0; } // 获取sys.getsizeof方法 PyObject* getsizeof_func = PyObject_GetAttrString(sys_module, "getsizeof"); Py_DECREF(sys_module); // 模块引用可提前释放 if (!getsizeof_func || !PyCallable_Check(getsizeof_func)) { if (getsizeof_func) Py_DECREF(getsizeof_func); PyErr_Print(); return 0; } // 调用getsizeof(obj) PyObject* result = PyObject_CallFunctionObjArgs(getsizeof_func, obj, NULL); Py_DECREF(getsizeof_func); if (!result) { PyErr_Print(); return 0; } // 转换为size_t类型并合法性校验 long tmp = PyLong_AsLong(result); size_t size = (tmp >= 0) ? (size_t)tmp : 0; Py_DECREF(result); return size; }
修正说明
- 用
PyImport_ImportModule正确导入sys模块 - 增加了所有关键步骤的错误检查,避免空指针访问
- 移除了不必要的引用计数操作,避免内存错误
- 使用
PyObject_GetAttrString简化方法获取流程 - 对返回的长整型值做合法性判断,避免负数转换问题
内容的提问来源于stack exchange,提问作者TCA 166
相关产品推荐
相关产品推荐

