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

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

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

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

== 8021 == по 0x3FDA61118F: tls_get_addr_tail (в /lib64/ld-2.12.so)

== 8021 == по 0x3FDA61165F: __tls_get_addr (в /lib64/ld-2.12.so)

== 8021 == от 0x3FE6ABBDCB: __cxa_get_globals (в /usr/lib64/libstdc++.so.6.0.13)

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

== 8021 == 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.

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

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

3 ответа

Решение

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

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

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

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

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

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

Заметка

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

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

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

Другие вопросы по тегам