You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 18:52:04