避免Boost日志中的泄漏—琐碎的使用
Avoid leak in Boost Log trivial usage
我正在从一个服务器端应用程序获得valgrind泄漏报告,该应用程序使用随boost 1.56分发的boostlog。valgrind报告是:
==8021==37088字节在1642 的丢失记录1613中肯定丢失1159个块
===8021===在0x4A05588处:memalign(vg_replace_malloc.c:727)
===8021===通过0x3FDA61118F:tls_get_addr_tail(在/lib64/ld-2.112.so中)
===8021===通过0x3FDA61165F:__tls_get_addr(在/lib64/ld-2.112.so中)
===8021===通过0x3FE6ABBDCB:__cxa_get_globals(在/usr/lib64/libstdc++.so.6.0.13中)
===8021===通过0x730C528:boost::log::v2_mt_posix::aux::unhanded_exception_count()(在/opt/sesteksdk/lib/libboost_log.so.1.56.0中)
===8021===通过0x5D54D1F:setek::mrcp::audio::recognition::AsynchronousRecognizer::Notify(sestek::voice::recgnition::IRecognizerNotification const*)(record_ostream.hp:259)
此泄漏来自一个简单的行:LOGGER(debug)<< _chanProp->GetId() << " got recognition ended notification from recognizer";
我们仅从一次短暂的测试运行中就得到了其中5次泄漏。
我们使用文本文件后端,带有同步接收器,自动刷新打开。基本上:
void InitializeFileLog(const std::string & logDir)
{
boost::shared_ptr< logging::core > loggingCore = logging::core::get();
loggingCore->add_global_attribute("TimeStamp", attrs::local_clock());
string logPath = logDir + "/gvzmrcpsr_%N.txt";
boost::shared_ptr< sinks::text_file_backend > backend =
boost::make_shared< sinks::text_file_backend >(
// file name pattern
keywords::file_name = logPath,
// rotate the file upon reaching 5 MiB size...
keywords::rotation_size = 5 * 1024 * 1024,
// ...or at midnight, whichever comes first
keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0)
);
backend->auto_flush(true);
// Wrap it into the frontend and register in the core.
// The backend requires synchronization in the frontend.
typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t;
boost::shared_ptr< sink_t > sink = boost::make_shared< sink_t>(backend);
loggingCore->add_sink(sink);
sink->flush();
sink->set_formatter
(
expr::stream
<< expr::attr< boost::posix_time::ptime >("TimeStamp")
<< " : [" << expr::attr< sestek::log::LogLevel >("Severity")
<< "] " << expr::smessage
);
backend->set_file_collector(sinks::file::make_collector(
// rotated logs will be moved here
keywords::target = logDir + "/old_mrcpsr_plugin_logs",
// oldest log files will be removed if the total size reaches 100 MiB...
keywords::max_size = 100 * 1024 * 1024,
// ...or the free space in the target directory comes down to 50 MiB
keywords::min_free_space = 50 * 1024 * 1024
));
try
{
backend->scan_for_files(sinks::file::scan_all);
}
catch(std::exception & )
{
//LOGGER(sestek::log::fatal) << "exception during scanning : " << e.what();
}
}
该系统使用devtoolkit2.0在centos6.6上编译并运行。gcc版本为4.8.2。
那么,我们使用boost日志是否存在问题?或者boost日志真的有这样的问题吗。我认为我们的使用可以被认为是微不足道的,我们只是在启动期间运行上面的配置代码。
注意:尽管单个泄漏大小可能足够小,但我们的软件是作为服务器上的服务运行的,因此这种重复泄漏对我们来说是有问题的。
Boost Log与许多其他日志库一样,在内部使用tl。当线程终止时,日志系统很难(有时似乎不可能)清理tls变量。Boost也面临同样的困难。
对于包含日志记录代码的长时间运行的应用程序来说,分离许多线程并在任务完成时终止它们并不是一个好的用途。在多任务系统中,更好的方法是使用线程池,而不是每次都启动新的线程。
我将应用程序转换为使用线程池,问题中的泄漏已经消失。Tls变量仍然存在,但由于现在线程被重用,Tls变量也被其相应的线程重用。
我真的不明白这个问题。你出示泄漏的证据,然后问"泄漏了吗"。是的。这并不奇怪。记录器使用线程本地"singletons"。根据你组织线程的方式,正确地删除这些线程是可能的/几乎不可能的。
是时候进行SSCCE并点击有关正确停堆顺序的文件了。
备注
关闭记录器是出了名的困难。您需要处理在关机期间需要记录某些内容的可能性(一种设计气味);更糟糕的是,不同的汇可能相互依赖,并防止以任何特定的顺序关闭)。
相当多的框架只是让操作系统来清理。
PS没有任何内容表明重复泄漏,因为它看起来像是每个线程的泄漏。
泄漏的对象是C++运行时的内部部分,它不是由Boost.Log显式创建的。从我所看到的,这个对象是每个线程创建的,因此应该在线程终止时销毁。你对Boost.Log的使用对我来说似乎很好。
- 理解boost::asio-async_read在无需读取内容时的行为
- valgrind-hellgrind与泄漏检查的结果不同
- boost::进程间消息队列引发错误
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- cmake如何在fedora工作站中找到boost静态库包
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- 内存泄漏使用boost::存档::binary_iarchive
- 内存泄漏在async_handshake使用boost beast和openssl
- 将GoogleMock与Boost::Shared Pointers一起使用时泄漏的Mock对象
- 使用Eigen和boost::线程的C++中出现奇怪的内存泄漏
- 避免Boost日志中的泄漏—琐碎的使用
- 使用boost日志,Valgrind检查内存泄漏
- 可能是boost ssl握手功能存在一些内存泄漏
- C++使用boost::ptr_vector泄漏内存
- Boost.thread可能存在内存泄漏
- 使用boost python返回narray的字典会导致内存泄漏
- 使用boost::ptr_vector的c++内存泄漏
- 理解在使用boost::asio和boost::thread时的内存泄漏
- 来自 Boost::asio 套接字async_read_some操作的内存泄漏
- 我的程序泄漏了boost::shared_ptr拥有的资源