Подход к проектированию, данные таблицы строк, переменные, использование памяти stl

У меня есть такой старый класс структуры: typedef vector<vector<string>> VARTYPE_T;, который работает как одна переменная. Эта переменная может хранить от одного значения в списке до данных, таких как таблица. Большинство значений являются длинными, двойными, строковыми или двойными [3] для координат (x, y, z). Я просто конвертирую их по мере необходимости. Переменные управляются на карте следующим образом: map<string,VARTYPE_T *> где строка содержит имя переменной. Конечно, они завернуты в классы. Также у меня есть дерево узлов, где каждый узел может содержать одну из этих карт переменных.

Используя для этого VS 2008 SP1, я обнаружил много фрагментации памяти. При сравнении с stlport оказалось, что stlport работает быстрее (20%) и использует меньше памяти (30% для моих тестов).

Итак, вопрос: какова наилучшая реализация для решения этого требования с быстрой и правильно используемой памятью? Должен ли я написать собственный распределитель, например распределитель пула. Как бы вы это сделали?

Заранее спасибо,

Хауи


person howieh    schedule 09.03.2010    source источник
comment
Вы отключили функции безопасности, такие как проверка итератора с помощью VC++?   -  person UncleBens    schedule 09.03.2010


Ответы (1)


Измените typedef vector<vector<string>> VARTYPE_T; на typedef deque<deque<string>> VARTYPE_T; и проверьте, сохраняется ли фрагментация памяти.

Кстати, как вы измеряете это с VS 2008 SP1?

Обновление: я знаю, как HP справляется с фрагментацией памяти HP-UX. После поиска я нашел интересную ссылку Низкая фрагментация Куча. Это цитата: The low-fragmentation heap (LFH) helps to reduce heap fragmentation. Мне это интересно, т.к. похоже на подход HP к фрагментации памяти, судя конечно из его описания. Я думаю (помимо использования deque) это еще одна хорошая идея попробовать и проверить. `

Обновление 2: 1) Скорость. Вы раньше ничего не говорили о скорости, поэтому у меня нет никаких указаний, чтобы дать вам хороший совет. Я также не знаю, где ваша программа проводит большую часть времени во время выполнения.

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

2) Использование памяти. Вы на самом деле пишете серверное приложение, работающее в течение нескольких дней, и должны сильно заботиться о потреблении памяти? Тогда я уже говорил вам, используйте Low-fragmentation Heap в Windows и попробуйте использовать размеры блоков меньше 16 КБ. Также избавьтесь от утечек памяти. Конечно, проверьте, но насколько я понимаю, Low-fragmentation Heap должен передавать вам новости.

3) Если вы пишете серверное приложение, то std::vector иногда не лучший выбор. Он выделяет память в одном блоке. Если он превышает 16 КБ, это может привести к фрагментации памяти.

4) Наконец, посмотрите, как выглядит хороший отчет от HP-UX о распределении памяти (чтобы найти фрагментацию памяти):

Actual Heap Usage:
    Heap Start  =   0x60000000000fea38
    Heap End    =   0x6000000026580000
    Heap Size   =   642258376 bytes

Outstanding Allocations:
    251948524 bytes allocated in 4239425 blocks
                              Detailed Report

-------------------------------------------------------------------------
65343264 bytes in 1361318 blocks (25.94% of all bytes allocated)
These range in size from 48 to 48 bytes and are allocated
#0  stlp_std::__malloc_alloc::allocate(unsigned long&)   from ./libstlport.so.5.1
#1  boost::multi_index::detail::ordered_index<boost::multi_index::identity<csubs::clnt_tax_hist_t>, stlp_std::less<csubs::clnt_tax_hist_t>, boost::multi_index::detail::nth_layer<1, csubs::clnt_tax_hist_t, boost::multi_index::indexed_by<boost::multi_index::ordered_non_unique<boost::multi_index::identity<csubs::clnt_tax_hist_t>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, hrs_allocator::counting_allocator<csubs::clnt_tax_hist_t, (hrs_allocator::allocator_enums)9> >, boost::mpl::vector0<mpl_::na>, boost::multi_index::detail::ordered_non_unique_tag>::insert(csubs::clnt_tax_hist_t const&)   at _alloc.h:381



-------------------------------------------------------------------------
47510512 bytes in 848402 blocks (18.86% of all bytes allocated)
These range in size from 56 to 56 bytes and are allocated
#0  stlp_std::__malloc_alloc::allocate(unsigned long&)   from ./libstlport.so.5.1
#1  csubs::cache_impl<csubs::subs_data_t, csubs::search_policy_range<false>, csubs::erase_policy_range, hrs_allocator::counting_allocator<csubs::subs_data_t, (hrs_allocator::allocator_enums)5>, boost::multi_index::multi_index_container<csubs::subs_data_t, boost::multi_index::indexed_by<boost::multi_index::ordered_non_unique<boost::multi_index::identity<csubs::subs_data_t>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, hrs_allocator::counting_allocator<csubs::subs_data_t, (hrs_allocator::allocator_enums)5> > >::put(csubs::subs_data_t const&)   at _alloc.h:381
#2  csubs::db_cache_loader<csubs::cache_impl<csubs::subs_data_t, csubs::search_policy_range<false>, csubs::erase_policy_range, hrs_allocator::counting_allocator<csubs::subs_data_t, (hrs_allocator::allocator_enums)5>, boost::multi_index::multi_index_container<csubs::subs_data_t, boost::multi_index::indexed_by<boost::multi_index::ordered_non_unique<boost::multi_index::identity<csubs::subs_data_t>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, hrs_allocator::counting_allocator<csubs::subs_data_t, (hrs_allocator::allocator_enums)5> > >, csubs::ctrl_loader_nocheck>::operation()   at cache_subs_loaders.h:121
#3  csubs::group_subs_cache::load_caches_from_db(db_date const&, csubs::cache_options const&, otl_connect&, csubs::cache_stat*)   at ./caches/cache_subs_caches.cpp:1452

и так далее.

person Community    schedule 09.03.2010
comment
Вот как я получаю использование памяти: double MemoryGetWorkingSetSize() { DWORD curPro = GetCurrentProcessId(); ОБРАБАТЫВАТЬ hProcess; PROCESS_MEMORY_COUNTERS pmc; hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, curPro); если (NULL == hProcess) вернуть -1.0; if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) ) { double rc = pmc.WorkingSetSize/1024.0; CloseHandle(hProcess); вернуть рс; } CloseHandle(hProcess); возврат -1,0; } / - person howieh; 09.03.2010
comment
Ваша функция возвращает WorkingSetSize в килобайтах. Почему вы говорите о memory fragmentation? - person ; 09.03.2010
comment
Хорошо.. я тоже использую средство просмотра процессов, Хоуи - person howieh; 09.03.2010
comment
Извините, не понял вашу точку зрения по поводу средства просмотра процессов. Способен ли он сказать вам, как именно выделяется память с помощью malloc()? - person ; 09.03.2010
comment
Может быть, это изображение может дать лучший обзор. Забудьте о старой структуре. Что лучше для редизайна? img696.imageshack.us/img696/7633/cellstructure.jpg Спасибо, Хоуи. - person howieh; 09.03.2010
comment
Какая цель редизайна? Все еще избавляетесь от фрагментации памяти? Или что-то другое. - person ; 09.03.2010
comment
Мы хотим использовать этот материал больше для проекта и хотим иметь хороший (возможно, лучший, чем существующий) подход к скорости и использованию памяти. Это старые вещи. Сегодня никто не будет реализовывать это так, как оно есть (прямо наследовать от классов stl и т. д.). Также реализация должна быть обернута и скрыта для пользователей. Так что, если мы делаем много нового, мы должны думать об этом. - person howieh; 09.03.2010
comment
@skwllsp Спасибо. Во-первых: я перешел с вектора на deque без существенной разницы. Но я понимаю главное отличие. Вектор выделяет блочно, а дек - нет. Во-вторых: я попробовал много простых тестов, и получилось так, как вы написали: разговор между string и long/double занимает много времени. Я также пробовал с объединением, где вместо строки доступен указатель void. Так что это лучшая (проверенная) структура ячейки объединения для меня сейчас: long m_long; двойной m_double[3]; недействительным *m_vPointer; - person howieh; 11.03.2010
comment
С помощью этого указателя я могу прикрепить строку или другую сложную структуру. Я подумаю об этом.. Хоуи - person howieh; 11.03.2010
comment
Я также тестирую boost::any и boost::variant. Простая структура выше всегда быстрее. boost::any требует меньше памяти, но в 3 раза медленнее. Спасибо - person howieh; 16.03.2010
comment
Я вижу, что вы очень заботитесь о скорости. Вы ничего не рассказали о своей задаче, но, возможно, вам будет полезно использовать потоки в своем приложении. Конечно стоит только если у вас многоядерный процессор. - person ; 16.03.2010
comment
Я переработал часть приложения в соответствии со своим подходом. Результат: на 40% меньше использование памяти, на 40-50% больше скорости. @skwllsp Темы в таком программном обеспечении непросты. Но вы правы, возможно, стоит это проверить. - person howieh; 17.03.2010