Избегайте утечки в обычном использовании журнала Boost Log

Я получаю отчеты об утечке valgrind с приложения на стороне сервера, использующего boostlog, который распространяется с повышением 1.56. отчет valgrind:

== 8021 == 37,088 байт в 1159 блоках определенно потеряно в записи потерь 1,613 из 1,642

== 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:: признание:: AsynchronousRecognizer:: Notify (sestek:: voice:: признание:: 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();

        }

    }

Система скомпилирована и запущена на centos 6.6 с помощью devtoolkit2.0. Версия gcc - 4.8.2.

Итак, есть ли проблема в использовании журнала boost? Или у boost log действительно есть такие проблемы. Я думаю, что наше использование можно считать тривиальным, мы просто запускаем код конфигурации выше во время запуска.

Примечание. Несмотря на то, что один размер утечки может быть достаточно небольшим, наше программное обеспечение запускается как служба на сервере, поэтому такая повторяющаяся утечка является проблематичной для нас.

Ответ 1

Boost Log - как и многие другие библиотеки протоколирования - использует tls внутри. Трудно (и иногда кажется невозможным), чтобы система протоколирования очищала переменные tls, когда поток завершается. Усилия сталкиваются с теми же трудностями.

Для долговременного приложения, которое содержит код ведения журнала, отключение многих потоков и их завершение, когда их задача выполнена, не является хорошим использованием. Лучшим подходом в сильно многозадачной системе является использование пула потоков вместо того, чтобы начинать новые потоки каждый раз.

Я преобразовал приложение в использование пула потоков, и утечки в вопросе исчезли. Переменные Tls все еще существуют, но поскольку теперь потоки повторно используются, переменные tls также повторно используются соответствующими потоками.

Ответ 2

Я действительно не понимаю. Вы показываете признаки утечки и спрашиваете: "Это утечка". Ну да. Это неудивительно. Журналы используют потоковые локальные "синглтоны". В зависимости от того, как вы организовали свои потоки, будет возможно/почти невозможно правильно вырвать их.

Время, чтобы сделать SSCCE и ударить документацию по соответствующим последовательностям выключения.

Примечание

Завершение работы логгеров, как известно, сложно. Вам нужно иметь дело со случайностью, что что-то нужно записывать во время выключения (запах дизайна); Хуже того, разные раковины могут зависеть друг от друга и предотвращать выключение в любом конкретном порядке).

Довольно много фреймворков просто оставляют его ОС для очистки.

PS Ничто не указывает на повторяющуюся утечку, поскольку она похожа на утечку в потоке.

Ответ 3

Просочившийся объект является внутренней частью среды выполнения С++, которая явно не создается Boost.Log. Из того, что я вижу, этот объект создается для потока и как таковой должен быть уничтожен, когда поток завершается. Ваше использование Boost.Log кажется мне прекрасным.