FastDeploy icon indicating copy to clipboard operation
FastDeploy copied to clipboard

重复刷新模型造成的内存泄露问题

Open Algabeno opened this issue 1 year ago • 6 comments


温馨提示:根据社区不完全统计,按照模板提问,可以加快回复和解决问题的速度


环境

【FastDeploy版本】: deploy自己编译 【编译命令】export ENABLE_ORT_BACKEND = OFF export ENABLE_PADDLE_BACKEND = OFF export ENABLE_OPENVINO_BACKEND = OFF export ENABLE_VISION = ON export ENABLE_TEXT = OFF export ENABLE_TRT_BACKEND = OFF export WITH_GPU = OFF 【系统平台】: Windows 11 【硬件】: 笔记本 intel i7-1260p 【编译语言】:C++

问题日志及出现问题的操作流程

由于工程要求,每次刷新相机之后都需要重新刷新一次AI模型。经过测试发现,如果重复调用多次模型初始化函数,会造成内存泄漏,每隔10s~20s会泄露0.3M。下面是我的初始化函数 bool OcrModel::InitModel(OcrModelConfig& config) { // 将 GBK 路径转换为 UTF-8 路径 std::string model_dir = config.strNetPath;

// 构建模型文件的路径
std::filesystem::path model_path = std::filesystem::path(model_dir) / "inference.pdmodel";
std::filesystem::path params_path = std::filesystem::path(model_dir) / "inference.pdiparams";
std::filesystem::path config_path = std::filesystem::path(model_dir) / "inference.yaml";

std::string& strError = config.strError;

// 检查文件是否存在
if (!fs::exists(model_path) || !fs::exists(params_path)) {
    config.strError = "Model or parameter file does not exist.";
    return false;
}

// 初始化模型
option.UseCpu();  // 使用 CPU
try {
    model = fastdeploy::vision::ocr::DBDetector(model_path.string(), params_path.string(), option);
}
catch (const std::exception& e) {
    strError = "Failed to create the OCR model: " + std::string(e.what());
    return false;
}

if (!model.Initialized()) {
    strError = "Failed to initialize the OCR model.";
    return false;
}

try {
    model.GetPostprocessor().SetDetDBThresh(config.det_db_thresh);
    model.GetPostprocessor().SetDetDBBoxThresh(config.det_db_box_thresh);
    model.GetPostprocessor().SetDetDBUnclipRatio(config.det_db_unclip_ratio);
}
catch (const std::exception& e) {
    strError = "Failed to set post-processing parameters: " + std::string(e.what());
    return false;
}
return true;

}

Algabeno avatar Aug 26 '24 08:08 Algabeno

如果你是每一次都要加载模型,建议把加载模型的操作放在子进程里,这样进程结束,占用资源会自动释放

Jiang-Jia-Jun avatar Aug 27 '24 02:08 Jiang-Jia-Jun

如果你是每一次都要加载模型,建议把加载模型的操作放在子进程里,这样进程结束,占用资源会自动释放

FastDeploy是一个很棒的框架,我在尝试将这个框架应用到真实的生产环境中。如果把加载模型的操作放在子进程会造成不必要的开销和加深算法的复杂度,能否实现在同进程主动释放内存

Algabeno avatar Aug 27 '24 03:08 Algabeno

在你的代码里,是会循环调用这一行是吗model = fastdeploy::vision::ocr::DBDetector(model_path.string(), params_path.string(), option);

也许你可以试一下将model的声明也放在一个作用域内,例如

{
  Model model = fastdeploy::xxxxx;
  model = fastdeploy::vision::ocr::DBDetector....
}

测试看下是否可以在出作用域后自动释放

Jiang-Jia-Jun avatar Aug 28 '24 02:08 Jiang-Jia-Jun

在你的代码里,是会循环调用这一行是吗model = fastdeploy::vision::ocr::DBDetector(model_path.string(), params_path.string(), option);

也许你可以试一下将model的声明也放在一个作用域内,例如

{
  Model model = fastdeploy::xxxxx;
  model = fastdeploy::vision::ocr::DBDetector....
}

测试看下是否可以在出作用域后自动释放

十分感谢您的解答,我的代码会在特定情况下重复调用多次model = fastdeploy::vision::ocr::DBDetector(model_path.string(), params_path.string(), option);。我尝试了将model的声明放在一个作用域内,无法解决内存泄漏的问题。作用域只能释放掉栈对象。而初始化模型的代码似乎存在着一些堆对象没有显式释放,导致在刷新模型时会有些许内存泄漏,这并不利于一个软件的长期运行。

Algabeno avatar Aug 28 '24 03:08 Algabeno

.h檔定義

fastdeploy::pipeline::PPOCRv3* ppocr_v3 = NULL;
fastdeploy::vision::ocr::DBDetector* det_model = NULL;
fastdeploy::vision::ocr::Classifier* cls_model = NULL;
fastdeploy::vision::ocr::Recognizer* rec_model = NULL;

.cpp檔子程序初始化類似這樣

if (rec_model)
    {
        delete rec_model;
        rec_model = NULL;
    }

    if (det_model)
    {
        delete det_model;
        det_model = NULL;
    }

    if (det_model_exist)
    {
        det_model = new fastdeploy::vision::ocr::DBDetector(
            det_model_file, det_params_file, det_option);
        assert(det_model.Initialized());
    }
       
    if (cls_model_exist)
    {
        cls_model = new fastdeploy::vision::ocr::Classifier(
            cls_model_file, cls_params_file, cls_option);
        assert(cls_model.Initialized());
    }

  rec_model = new fastdeploy::vision::ocr::Recognizer(
      rec_model_file, rec_params_file, rec_label_file, rec_option);

  assert(rec_model.Initialized());

我包dll給其他程序或是直接執行都有觀察到會釋放記憶體

Hommoner avatar Mar 28 '25 08:03 Hommoner

.h檔定義

fastdeploy::pipeline::PPOCRv3* ppocr_v3 = NULL;
fastdeploy::vision::ocr::DBDetector* det_model = NULL;
fastdeploy::vision::ocr::Classifier* cls_model = NULL;
fastdeploy::vision::ocr::Recognizer* rec_model = NULL;

.cpp檔子程序初始化類似這樣

if (rec_model)
    {
        delete rec_model;
        rec_model = NULL;
    }

    if (det_model)
    {
        delete det_model;
        det_model = NULL;
    }

    if (det_model_exist)
    {
        det_model = new fastdeploy::vision::ocr::DBDetector(
            det_model_file, det_params_file, det_option);
        assert(det_model.Initialized());
    }
       
    if (cls_model_exist)
    {
        cls_model = new fastdeploy::vision::ocr::Classifier(
            cls_model_file, cls_params_file, cls_option);
        assert(cls_model.Initialized());
    }

  rec_model = new fastdeploy::vision::ocr::Recognizer(
      rec_model_file, rec_params_file, rec_label_file, rec_option);

  assert(rec_model.Initialized());

我包dll給其他程序或是直接執行都有觀察到會釋放記憶體

ni

.h檔定義

fastdeploy::pipeline::PPOCRv3* ppocr_v3 = NULL;
fastdeploy::vision::ocr::DBDetector* det_model = NULL;
fastdeploy::vision::ocr::Classifier* cls_model = NULL;
fastdeploy::vision::ocr::Recognizer* rec_model = NULL;

.cpp檔子程序初始化類似這樣

if (rec_model)
    {
        delete rec_model;
        rec_model = NULL;
    }

    if (det_model)
    {
        delete det_model;
        det_model = NULL;
    }

    if (det_model_exist)
    {
        det_model = new fastdeploy::vision::ocr::DBDetector(
            det_model_file, det_params_file, det_option);
        assert(det_model.Initialized());
    }
       
    if (cls_model_exist)
    {
        cls_model = new fastdeploy::vision::ocr::Classifier(
            cls_model_file, cls_params_file, cls_option);
        assert(cls_model.Initialized());
    }

  rec_model = new fastdeploy::vision::ocr::Recognizer(
      rec_model_file, rec_params_file, rec_label_file, rec_option);

  assert(rec_model.Initialized());

我包dll給其他程序或是直接執行都有觀察到會釋放記憶體 @Hommoner 你是否有尝试过重复调用多次model = fastdeploy::vision::ocr::DBDetector(model_path.string(), params_path.string(), option);,因为软件需要在设备上长时间运行,所以需要考虑到重复初始化模型,而我观察到重复调用多次会造成泄露0.3M内存,

Algabeno avatar Apr 21 '25 02:04 Algabeno