TensorFlow C API内存释放问题求助:Valgrind检测到内存泄漏
TensorFlow C API内存泄漏排查与修复
使用TensorFlow C API时遇到内存释放问题,Valgrind检测到存在内存泄漏,其中包含1块112字节的明确泄漏点,目前无法确定遗漏的释放操作,怀疑和类型转换有关但未确认。
Valgrind检测信息
==60261== by 0x5958E1A: TF_LoadSessionFromSavedModel (in /usr/local/lib/libtensorflow.so.2.11.0) ==60261== by 0x10A136: CreateModel (in /home/murage/Desktop/06/main) ==60261== ==60261== LEAK SUMMARY: ==60261== definitely lost: 0 bytes in 0 blocks ==60261== indirectly lost: 0 bytes in 0 blocks ==60261== possibly lost: 636,088 bytes in 16,611 blocks ==60261== still reachable: 13,565,248 bytes in 208,524 blocks ==60261== of which reachable via heuristic: ==60261== newarray : 13,448 bytes in 11 blocks ==60261== suppressed: 0 bytes in 0 blocks ==60261== Reachable blocks (those to which a pointer was found) are not shown.
相关代码
typedef struct train *Model; struct train { const char *modelDirectory; const char *tags; TF_Graph *graph; TF_Status *status; TF_SessionOptions *sessionOptions; TF_Buffer *runOptions; TF_Session *session; TF_Output *input; TF_Output *output; int numberOfInputs; int numberOfOutputs; TF_Tensor **inputValues; TF_Tensor **outputValues; float *data; int dataLength; }; Model CreateModel(const char *modelDirectory, const char *tags, char *inputLayerName, char *outputLayerName, int dataLength) { Model model = malloc(sizeof(*model)); int numberOfTags = 1; model->numberOfInputs = 1; model->numberOfOutputs = 1; model->modelDirectory = modelDirectory; model->tags = tags; model->graph = TF_NewGraph(); model->status = TF_NewStatus(); model->sessionOptions = TF_NewSessionOptions(); model->runOptions = NULL; model->session = TF_LoadSessionFromSavedModel(model->sessionOptions, model->runOptions, model->modelDirectory, &model->tags, numberOfTags, model->graph, NULL, model->status); assert(TF_GetCode(model->status) == TF_OK); model->input = (TF_Output*)malloc(sizeof(TF_Output) * model->numberOfInputs); model->output = (TF_Output*)malloc(sizeof(TF_Output) * model->numberOfOutputs); TF_Output inputLayer = {TF_GraphOperationByName(model->graph, inputLayerName), 0}; TF_Output outputLayer = {TF_GraphOperationByName(model->graph, outputLayerName), 0}; assert(outputLayer.oper != NULL); assert(inputLayer.oper != NULL); model->input[0] = inputLayer; model->output[0] = outputLayer; model->inputValues = (TF_Tensor**)malloc(sizeof(TF_Tensor*)*model->numberOfInputs); model->outputValues = (TF_Tensor**)malloc(sizeof(TF_Tensor*)*model->numberOfOutputs); model->data = calloc(dataLength, sizeof(float)); model->dataLength = dataLength; return model; } //Destroy Model void DestroyModel(Model model) { TF_DeleteSessionOptions(model->sessionOptions); TF_DeleteSession(model->session, model->status); TF_DeleteStatus(model->status); TF_DeleteGraph(model->graph); TF_DeleteBuffer(model->runOptions); free(model->input); free(model->output); free(model->inputValues); free(model->outputValues); free(model->data); free(model); }
问题分析与修复方案
1. 遗漏TF_Tensor对象释放
代码中仅分配了inputValues和outputValues指针数组,但如果在后续使用中(比如调用TF_NewTensor创建输入张量、或通过TF_SessionRun获取输出张量)给这些数组赋值了TF_Tensor实例,就必须手动释放这些张量对象,否则会造成内存泄漏。
在DestroyModel中添加张量释放逻辑:
// 释放输入输出Tensor(如果已创建) for (int i = 0; i < model->numberOfInputs; i++) { if (model->inputValues[i] != NULL) { TF_DeleteTensor(model->inputValues[i]); } } for (int i = 0; i < model->numberOfOutputs; i++) { if (model->outputValues[i] != NULL) { TF_DeleteTensor(model->outputValues[i]); } }
2. 不必要的类型转换
C语言中malloc返回void*,可以直接赋值给任意指针类型,代码中的强制转换属于冗余操作,可直接移除:
// 原代码的强制转换可删除 model->input = malloc(sizeof(TF_Output) * model->numberOfInputs); model->output = malloc(sizeof(TF_Output) * model->numberOfOutputs); model->inputValues = malloc(sizeof(TF_Tensor*) * model->numberOfInputs); model->outputValues = malloc(sizeof(TF_Tensor*) * model->numberOfOutputs);
3. 优化资源释放顺序
调整DestroyModel的释放顺序,先释放依赖其他资源的对象,避免潜在的悬空指针问题:
void DestroyModel(Model model) { // 1. 释放输入输出Tensor for (int i = 0; i < model->numberOfInputs; i++) { if (model->inputValues[i] != NULL) { TF_DeleteTensor(model->inputValues[i]); } } for (int i = 0; i < model->numberOfOutputs; i++) { if (model->outputValues[i] != NULL) { TF_DeleteTensor(model->outputValues[i]); } } // 2. 删除TensorFlow核心对象(session依赖graph,先删session再删graph) TF_DeleteSession(model->session, model->status); TF_DeleteGraph(model->graph); TF_DeleteSessionOptions(model->sessionOptions); TF_DeleteStatus(model->status); // 对NULL调用TF_DeleteBuffer是安全的,但添加判断更严谨 if (model->runOptions != NULL) { TF_DeleteBuffer(model->runOptions); } // 3. 释放手动分配的内存 free(model->input); free(model->output); free(model->inputValues); free(model->outputValues); free(model->data); free(model); }
关于Valgrind报告的补充说明
报告中的possibly lost和still reachable部分,多数是TensorFlow内部的全局缓存或初始化资源,属于正常现象,不会影响程序运行,无需刻意处理。你提到的112字节泄漏点,大概率是遗漏了TF_Tensor的释放,按照上述方案修复后即可解决。
内容的提问来源于stack exchange,提问作者murage kibicho
相关产品推荐
相关产品推荐

