Проблема быстродействия. У меня есть задача, которая активно использует динамическую память (память выделяется по мере необходимости небольшими кусками и затем освобождается), по логике программы может возникнуть необходимость выделить несколько кусков по несколько килобайт. После выделения этих самых килобайт скорость выполнения сильно падает (разница даже не в разы а на порядки).
Мне необходимо, чтобы скорость выполнения задачи не зависила от дополнительного выделения памяти (во всяком случае отличалась не в разы). Может что посоветуете ?
18.10.04 21:38: Перенесено модератором из 'C/C++' — Павел Кузнецов
Здравствуйте, alex74, Вы писали:
A>Проблема быстродействия. У меня есть задача, которая активно использует динамическую память (память выделяется по мере необходимости небольшими кусками и затем освобождается), по логике программы может возникнуть необходимость выделить несколько кусков по несколько килобайт. После выделения этих самых килобайт скорость выполнения сильно падает (разница даже не в разы а на порядки).
A>Мне необходимо, чтобы скорость выполнения задачи не зависила от дополнительного выделения памяти (во всяком случае отличалась не в разы). Может что посоветуете ?
Для начала посмотреть профайлером, действительно ли замедление связано с распределением памяти.
Здравствуйте, alex74, Вы писали:
A>Мне необходимо, чтобы скорость выполнения задачи не зависила от дополнительного выделения памяти (во всяком случае отличалась не в разы). Может что посоветуете ?
Заюзай вот это счастье. Eсли сможешь разобратся все будет летать:
maq>Значительное снижение может быть если несколько потоков все время maq>выделяют/удаляют память, или если она сильно фрагментируется в процессе работы.
Я так подозреваю, что дело в том что если память выделяется в начале кучи это сказывается на все дальнейшие вызовы new. Видимо менаджер памяти просто сканирует кучу в поисках свободного блока.
maq>Если дело действительно в памяти (можно проверить профайлером), то можно maq>попробовать написать свои аллокаторы, а м/б подойдет и boost::pool
Что за boost::pool ?
maq>Опиши конкретную задачу, каким образом у тебя выделяется память?
Память выделяется оператором new. Если в терминах БД то задача следующая:
получаю запись (это в цикле)
при необходимости преобразовываю поля к нужному формату (например строковому, соответственно выделяю для этого память)
делаю необходимые вычисления
передаю полученный результат обратно
кроме того может передаваться информация о порядке записей, соответственно нужно выделять для нее память
Здравствуйте, Kluev, Вы писали:
K>Заюзай вот это счастье. Eсли сможешь разобратся все будет летать:
K>Компактный и быстрый распределитель: K>http://rsdn.ru/File/16157/mem_mgr.h
Чем он лучше ? Хотелось заранее определится насколько он мне подойдет.
A>Что за boost::pool ? http://www.boost.org/libs/pool/doc/index.html
Это вроде пула блоков/объектов одинакового размера, оптимально использовать
когда идет частое выделение, а потом частое удаление их же.
maq>>Опиши конкретную задачу, каким образом у тебя выделяется память?
A>Память выделяется оператором new. Если в терминах БД то задача следующая:
A>получаю запись (это в цикле) A>при необходимости преобразовываю поля к нужному формату (например строковому, соответственно выделяю для этого память) A>делаю необходимые вычисления A>передаю полученный результат обратно
Т.е. память в цикле выделяется/удаляется или остается выделенной?
Еще могу посоветовать выделять память не для отдельных записей, а блоками.
Можно для этой цели воспользоваться std::vector
A>кроме того может передаваться информация о порядке записей, соответственно нужно выделять для нее память
Здравствуйте, alex74, Вы писали:
A>Здравствуйте, Kluev, Вы писали:
K>>Заюзай вот это счастье. Eсли сможешь разобратся все будет летать:
K>>Компактный и быстрый распределитель: K>>http://rsdn.ru/File/16157/mem_mgr.h
A>Чем он лучше ? Хотелось заранее определится насколько он мне подойдет.
Этот менеджер написан специально чтобы решить проблему фрагментации памяти. У нас программа может работать считать непрерывно несколько дней подряд создавая и уничтожая большое число обьектов. В таких условиях стандартная куча начинает серьезно тормозить.
Здравствуйте, alex74, Вы писали:
A>Проблема быстродействия. У меня есть задача, которая активно использует динамическую память (память выделяется по мере необходимости небольшими кусками и затем освобождается), по логике программы может возникнуть необходимость выделить несколько кусков по несколько килобайт. После выделения этих самых килобайт скорость выполнения сильно падает (разница даже не в разы а на порядки).
A>Мне необходимо, чтобы скорость выполнения задачи не зависила от дополнительного выделения памяти (во всяком случае отличалась не в разы). Может что посоветуете ?
Использовать оператор new для выделения памяти в критических по времени приложениях — это плохо (работай с виртуальной памятью — т.к. Windows сама оптимизирует этот процесс).
Почитай про VirtualAlloc() и другие WIN API ф-ции позволяющие работать с virtual страницами памяти.
(так же просвятись по тому как Windows NT работает с памятью — Heap, виртуальный набор страниц и тд.)
Здравствуйте, white_znake, Вы писали:
A>>Мне необходимо, чтобы скорость выполнения задачи не зависила от дополнительного выделения памяти (во всяком случае отличалась не в разы). Может что посоветуете ?
_>Использовать оператор new для выделения памяти в критических по времени приложениях — это плохо (работай с виртуальной памятью — т.к. Windows сама оптимизирует этот процесс).
maq>Т.е. память в цикле выделяется/удаляется или остается выделенной? maq>Еще могу посоветовать выделять память не для отдельных записей, а блоками. maq>Можно для этой цели воспользоваться std::vector
Та что для полей — выделяется/удаляется, та что для индекса — остается до конца цикла (теоритически может увеличиватся/уменьшатся, но фактически остается постаянной и определяется при инициализации).
Для записей дополнительно ничего не выделяется, память выделяется только при обработке полей (выделение блоками тут не поможет).
Первоначально у меня вся память выделялась только по мере необходимости, тогда обработка порядка 600 тыс записей занимала более получаса. Потом я это все "оптимизировал" и выделеная память не освобождалась до конца цикла, а повторно использовалась. Выполнение сократилось до полутора минут. Но по всему коду были раставлены проверки типа выделина память или нет (проверялся указатель). Потом я решил еще больше "оптимизировать" и убрать проверки, перенеся выделение памяти для индекса в процедуру инициализации (момент определения параметров передаваемых данных). Скорость ваполнения составила примерно те же пол часа .
Дело в том что у меня в циксе может обрабатыватся несколько записей из разных источников и при этом производительность не должна так сильно падать.
A>Первоначально у меня вся память выделялась только по мере необходимости, тогда обработка порядка 600 тыс записей занимала более получаса. Потом я это все "оптимизировал" и выделеная память не освобождалась до конца цикла, а повторно использовалась. Выполнение сократилось до полутора минут. Но по всему коду были раставлены проверки типа выделина память или нет (проверялся указатель). Потом я решил еще больше "оптимизировать" и убрать проверки, перенеся выделение памяти для индекса в процедуру инициализации (момент определения параметров передаваемых данных). Скорость ваполнения составила примерно те же пол часа .
A>Дело в том что у меня в циксе может обрабатыватся несколько записей из разных источников и при этом производительность не должна так сильно падать.
Я так понял для одного источника один размер блока — соответственно создаешь столько
менеджеров сколько у тебя источников и вызываешь allocate у соответствующего типу
источника менеджера. Храни их до конца обработки цикла.
K>Этот менеджер написан специально чтобы решить проблему фрагментации памяти. У нас программа может работать считать непрерывно несколько дней подряд создавая и уничтожая большое число обьектов. В таких условиях стандартная куча начинает серьезно тормозить.
Как будет влиять выделеная память на дальнейшее выделение (я имею ввиду скорость работы) ? Кроме того, что решается проблема дефрагментации есть еще преимущества ?
Здравствуйте, Sir Wiz, Вы писали:
SW>Здравствуйте, white_znake, Вы писали:
A>>>Мне необходимо, чтобы скорость выполнения задачи не зависила от дополнительного выделения памяти (во всяком случае отличалась не в разы). Может что посоветуете ?
_>>Использовать оператор new для выделения памяти в критических по времени приложениях — это плохо (работай с виртуальной памятью — т.к. Windows сама оптимизирует этот процесс).
SW>Где про это можно почитать?
В MSDN прочитай про функции VirtualAlloc(), VirtualAllocEx(), VirtualFree(), VirtualProtectEx() и тд.
Эти ф-ции следует использовать в том, случае когда работаешь с большим объемом памяти и пишешь приложение критичное по времени.
(правда я читал о том, что производительность этих ф-ций зависит от размера стр. памяти — но сам не проверял).
Здравствуйте, alex74, Вы писали:
A>Проблема быстродействия. У меня есть задача, которая активно использует динамическую память (память выделяется по мере необходимости небольшими кусками и затем освобождается), по логике программы может возникнуть необходимость выделить несколько кусков по несколько килобайт. После выделения этих самых килобайт скорость выполнения сильно падает (разница даже не в разы а на порядки).
A>Мне необходимо, чтобы скорость выполнения задачи не зависила от дополнительного выделения памяти (во всяком случае отличалась не в разы). Может что посоветуете ?
Попробой проанализировать характер захватывания и освобождения памяти. Очень высокая производительность получится, если, например, удастся применить менеджер памяти, основанный на циклической очереди. Это когда выделяется память с головы очереди, а освобождается с хвоста. Но для эффективной работы такого менеджера надо, чтобы память освобождалась примерно в том же порядке, в котором она захватывалать (либо надо иметь запас свободной памяти). Причем точного соответствия отнюдь не требуется. Такой менеджер можно применить довольно часто. Это того стоит, ибо получим ОЧЕНЬ высокую производительность.