使用spdlog库调用Logger方法时内存泄漏,求代码问题排查
spdlog调用info/debug时内存泄漏问题排查
问题根源分析
1. 静态容器Sinks导致资源无法释放
代码中的Sinks是全局静态vector<spdlog::sink_ptr>,每次调用CreateLogger都会向其中添加新的sink实例:
CombinedLogger构造时会持有这些sink的shared_ptr(spdlog的logger内部会保存sink的引用)- 静态
Sinks本身也持有这些sink的shared_ptr,导致sink的引用计数永远无法降到0,无法被销毁 - 若多次调用
CreateLogger,会持续积累无法回收的sink对象,直接引发内存泄漏
2. 重复注册Logger的隐患
如果多次调用CreateLogger,重复执行spdlog::register_logger(CombinedLogger)会导致:
- spdlog全局注册表持有旧Logger的
shared_ptr - 静态
CombinedLogger又持有新Logger的引用,旧资源无法被回收,进一步加剧内存泄漏
修复方案
1. 移除静态sink容器,让Logger管理sink生命周期
将全局静态Sinks替换为函数内的局部容器,构造Logger后不再持有sink引用,让Logger完全负责sink的生命周期:
static std::shared_ptr<class spdlog::logger> CombinedLogger; bool CreateLogger(const char *loggerName, const char* logName, std::chrono::seconds interval, const char* logFormat) { // 局部sink容器,函数结束后自动销毁,不再持有sink引用 std::vector<spdlog::sink_ptr> local_sinks; local_sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); local_sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(logName)); CombinedLogger = std::make_shared<spdlog::logger>(loggerName, begin(local_sinks), end(local_sinks)); CombinedLogger->flush_on(spdlog::level::err); spdlog::flush_every(interval); CombinedLogger->set_pattern(logFormat); // 注册前检查是否已存在,避免重复注册 if (spdlog::get(loggerName) == nullptr) { spdlog::register_logger(CombinedLogger); } return true; }
2. 确保Logger只初始化一次
在调用CreateLogger时,通过std::call_once保证初始化操作仅执行一次,避免重复创建sink和Logger:
static std::once_flag logger_init_flag; std::call_once(logger_init_flag, [&](){ Logger::CreateLogger(name, logName, std::chrono::seconds(LogFlushTimeSec), "%Y-%m-%d | %H:%M:%S.%f| %n| %^%-10l%$| %v"); }); std::shared_ptr<spdlog::logger> logging = spdlog::get(LoggerName); logging->info("Execution Time and Date: {} ", std::ctime(&startTime));
3. 程序退出时清理spdlog资源
在程序退出阶段,调用spdlog::drop_all()销毁所有注册的Logger,释放相关内存资源:
// 程序退出前执行 spdlog::drop_all();
内容的提问来源于stack exchange,提问作者igor
相关产品推荐
相关产品推荐

