避免在Boost Log中使用漏洞

时间:2015-02-04 12:50:25

标签: c++ logging boost memory-leaks boost-log

我从服务器端应用程序获得valgrind泄漏报告,该应用程序使用与boost 1.56一起分发的boostlog。 valgrind报告是:

== 8021 == 1,159块中的37,088字节肯定会在损失记录1,613中丢失1,643

== 8021 ==在0x4A05588:memalign(vg_replace_malloc.c:727)

== 8021 == by 0x3FDA61118F:tls_get_addr_tail(在/lib64/ld-2.12.so中)

== 8021 == by 0x3FDA61165F:__ tls_get_addr(在/lib64/ld-2.12.so中)

== 8021 == by 0x3FE6ABBDCB:__ cxa_get_globals(在/usr/lib64/libstdc++.so.6.0.13中)

== 8021 == by 0x730C528:boost :: log :: v2_mt_posix :: aux :: unhandled_exception_count()(在/opt/sesteksdk/lib/libboost_log.so.1.56.0中)

== 8021 == by 0x5D54D1F:sestek :: mrcp :: audio :: recognition :: AsynchronousRecognizer :: Notify(sestek :: voice :: recognition :: IRecognizerNotification const *)(record_ostream.hpp: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在centos 6.6上编译和运行。 gcc版本是4.8.2。

因此我们使用升压日志存在问题吗?或者提升日志确实存在这样的问题。我认为我们的使用可以被认为是一个微不足道的,我们只是在启动时运行上面的配置代码。

注意:尽管单个泄漏大小可能足够小,但我们的软件在服务器上作为服务运行,因此这种重复泄漏对我们来说是个问题。

3 个答案:

答案 0 :(得分:3)

Boost Log - 与许多其他日志库一样 - 在内部使用tls。日志系统在线程终止时清理tls变量很困难(有时似乎不可能)。提升面临同样的困难。

对于包含日志记录代码的长时间运行的应用程序,分离许多线程并在完成任务时终止它们并不是一个好用途。在多任务处理系统中,更好的方法是使用线程池,而不是每次都启动新线程。

我将应用程序转换为使用线程池,问题中的泄漏已经消失。 Tls变量仍然存在,但由于现在线程被重用,因此tls变量也会被相应的线程重用。

答案 1 :(得分:1)

我真的不明白这个问题。你出示泄漏的证据,并问“它是否泄漏”。嗯,是。这并不奇怪。记录器使用线程本地“单例”。根据您的线程组织方式,可能/几乎不可能正确地撕下它们。

有时间制作SSCCE并查看正确关机序列的文档。

注意

关闭记录器非常困难。你需要处理在关机期间需要记录某事的机会(设计气味);更糟糕的是,不同的接收器可以相互依赖并防止以任何特定顺序关闭)。

相当多的框架只需将其留给操作系统进行清理。

PS 没有任何表示重复泄漏,因为它看起来像每个线程的泄漏。

答案 2 :(得分:1)

泄漏的对象是C ++运行时的内部部分,Boost.Log没有显式创建它。从我所看到的,这个对象是每个线程创建的,因此当线程终止时应该销毁它。您对Boost.Log的使用对我来说似乎很好。