Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > allocator для stl & boost


Автор: xbarmaglot 25.3.2016, 17:24
Возникла проблема при обработке больших потоков данных. Данные представляют из себя пакеты из сети разного размера.
Профайлер показал, что большое время уходит на выделение памяти и вызов деструкторов стандартных контейнеров.

Хотелось бы выделить большой кусок памяти и не вызывать оператор new при создании объекта, а просто резервировать память.
При удалении объекта хотелось бы тоже не удалять ее, а просто помечать, что она свободна.

Лишь только при нехватке перераспределить новую память.
Существует ли такой глобальный аллокатор для всей библиотеки stl/ищщые?

Автор: xvr 25.3.2016, 18:31
В стандартной stl нет (IMHO). Но никто не мешает написать свой и подсовывать его stl'ным контейнерам
Как то так -
Код

    template<typename _Tp> class allocator
    {
        public:
            typedef size_t     size_type;
            typedef ptrdiff_t  difference_type;
            typedef _Tp*       pointer;
            typedef const _Tp* const_pointer;
            typedef _Tp&       reference;
            typedef const _Tp& const_reference;
            typedef _Tp        value_type;

            template<typename _Tp1>
                struct rebind
                { typedef allocator<_Tp1> other; };

            allocator() throw() { }

            allocator(const allocator&) throw() { }

            template<typename _Tp1>
                allocator(const allocator<_Tp1>&) throw() { }

            ~allocator() throw() { }

            pointer
                address(reference __x) const { return &__x; }

            const_pointer
                address(const_reference __x) const { return &__x; }

            // NB: __n is permitted to be 0.  The C++ standard says nothing
            // about what the return value is when __n == 0.
            pointer
                allocate(size_type __n, const void* = 0)
                { return static_cast<_Tp*>(malloc(__n * sizeof(_Tp))); }

            // __p is not permitted to be a null pointer.
            void
                deallocate(pointer __p, size_type)
                { free(__p); }

            size_type
                max_size() const throw()
                { return size_t(-1) / sizeof(_Tp); }

            // _GLIBCXX_RESOLVE_LIB_DEFECTS
            // 402. wrong new expression in [some_] allocator::construct
            void
                construct(pointer __p, const _Tp& __val)
                { ::new(__p) _Tp(__val); }

#ifdef _MSC_VER
#pragma warning( push )
#pragma warning(disable: 4100)
#endif

            void
                destroy(pointer __p) { __p=__p; __p->_Tp::~_Tp(); }
#ifdef _MSC_VER
#pragma warning( pop )
#endif

    };

    template<typename _Tp>
        inline bool
        operator==(const allocator<_Tp>&, const allocator<_Tp>&)
        { return true; }

    template<typename _Tp>
        inline bool
        operator!=(const allocator<_Tp>&, const allocator<_Tp>&)
        { return false; }



    typedef std::basic_string<char, std::char_traits<char>, allocator<char> > string;

    template<class _Ty>
        class vector : public std::vector<_Ty,allocator<_Ty> > {};

    template<class _Kty, class _Ty>
        class map : public std::map<_Kty, _Ty, std::less<_Kty>, allocator<std::pair<const _Kty, _Ty> > > {};

    template<class _Kty, class _Ty>
        class multimap : public std::multimap<_Kty, _Ty, std::less<_Kty>, allocator<std::pair<const _Kty, _Ty> > > {};

    template<class _Kty>
        class set : public std::set<_Kty, std::less<_Kty>, allocator<_Kty> > {};



malloc/free заменяете на что надо (по вкусу)

Автор: baldman88 25.3.2016, 19:11
Возможно я неправ, но кажется немного странным то, что при работе с сетью на первое место выходит время на создание и уничтожение контейнеров. Может проблема именно в том, что не совсем правильно организована обработка полученных данных?

Автор: xbarmaglot 28.3.2016, 12:51
Ну мне приходят пакеты, я их разбираю и далее передаю сам пакет и методанные на обработку и запись.
Поэтому сам пакет приходится хранить (т.е. копировать) и удалять по необходимости.

Автор: xbarmaglot 28.3.2016, 16:04
порылся в интернете - есть готовые быстрые аллокаторы. Например, boost::fast_pool_allocator, TLFS, ...
А можно ли его установить для stl/boost по-умолчанию, или нужно указывать при создании каждого контейнера?

Автор: xvr 28.3.2016, 17:07
Цитата(xbarmaglot @  28.3.2016,  16:04 Найти цитируемый пост)
А можно ли его установить для stl/boost по-умолчанию,

Нет, но можно сделать свой namespace в котором переопределить (можно просто унаследовать) все stl/boost контейнеры (которые нужны) со своим алокатором

Автор: borisbn 29.3.2016, 16:03
Цитата(baldman88 @  25.3.2016,  19:11 Найти цитируемый пост)
Возможно я неправ, но кажется немного странным то, что при работе с сетью на первое место выходит время на создание и уничтожение контейнеров

Полностью согласен.

xbarmaglot, может у Вас режим Debug? Тогда перейдите в Release и Вы будете приятно удивлены.

Цитата(xbarmaglot @  28.3.2016,  12:51 Найти цитируемый пост)
Поэтому сам пакет приходится хранить (т.е. копировать) и удалять по необходимости. 

Можно ж хранить указатель на пакет в shared_ptr, и вся передача его из контейнера в контейнер будет занимать 4 (или 8) байт на пакет.

Автор: xbarmaglot 29.3.2016, 16:27
не совсем так. Мне приходит большой UDP, который фрагментируется на пакеты.
Само чтение из сокета - это копирование в локальный буфер.
Фрагментация - это второе копирование уже чистого пакета в контейнер.

А далее я уже гоняю умные указатели. Но когда пакет не нужен - удаление его.
Получается, что как минимум один конструктор и один деструктор. Вот они и тупят, как показал профайлер

Автор: xbarmaglot 20.5.2016, 14:45
Цитата(xvr @  28.3.2016,  17:07 Найти цитируемый пост)
Нет, но можно сделать свой namespace в котором переопределить (можно просто унаследовать) все stl/boost контейнеры (которые нужны) со своим алокатором

А можно ли как в пространстве std переопределить сам std::allocator?

Автор: xvr 20.5.2016, 15:44
Цитата(xbarmaglot @  20.5.2016,  14:45 Найти цитируемый пост)
А можно ли как в пространстве std переопределить сам std::allocator? 

Переопределить можно, но компилятор будет ругаться на дубликат определения  smile . Отключить тот, что есть в stl стандартным способом нельзя.
Но можно сделать частичную специализацию allocator для ваших типов (если этого вам хватит)

Автор: xbarmaglot 23.5.2016, 10:37
Цитата(xvr @  20.5.2016,  15:44 Найти цитируемый пост)
Но можно сделать частичную специализацию allocator для ваших типов (если этого вам хватит)

У меня достаточно много типов. Сложновато для всех аллокатор свой делать...

Может еще какие варианты есть ?

Автор: Alexeis 23.5.2016, 11:27
Цитата(xbarmaglot @  23.5.2016,  11:37 Найти цитируемый пост)
У меня достаточно много типов. Сложновато для всех аллокатор свой делать...

  Кому сложновато? xvr уже определил вам шаблонные классы для основных контейнеров. Нужно просто пройти рефракторингом по коду и переименовать названия контейнеров. Определять нужно не для каждой переменной, а 1 раз для каждого вида контейнера. В STL едва ли десяток контейнеров наберется и сомневаюсь что у вас используются все.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)