PaddlePaddle / FastDeploy

⚡️An Easy-to-use and Fast Deep Learning Model Deployment Toolkit for ☁️Cloud 📱Mobile and 📹Edge. Including Image, Video, Text and Audio 20+ main stream scenarios and 150+ SOTA models with end-to-end optimization, multi-platform and multi-framework support.
https://www.paddlepaddle.org.cn/fastdeploy
Apache License 2.0
2.91k stars 454 forks source link

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

Open Algabeno opened 2 weeks ago

Algabeno commented 2 weeks ago

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


环境

【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;

}

Jiang-Jia-Jun commented 2 weeks ago

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

Algabeno commented 2 weeks ago

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

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

Jiang-Jia-Jun commented 2 weeks ago

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

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

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

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

Algabeno commented 2 weeks ago

在你的代码里,是会循环调用这一行是吗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的声明放在一个作用域内,无法解决内存泄漏的问题。作用域只能释放掉栈对象。而初始化模型的代码似乎存在着一些堆对象没有显式释放,导致在刷新模型时会有些许内存泄漏,这并不利于一个软件的长期运行。