Предифиниране на new

Ако сте начинаещ, отделете малко време тук преди да посетите другите форуми.
Потребителски аватар
themean
Power User
Power User
Мнения: 871
Регистриран: 02 дек 2010 22:51

Предифиниране на new

Мнение от themean » 05 юли 2012 20:36

Разбрах, че било добре в някои случай да си предифинираш оператора new.Било доста по-добре от гледна точка на бързодействието а и не ти било правило heap-а на решето ако си заделяш цялата памет на веднъж.
Някой има ли опит с това . Ако има такива с опит нека кажат по някоя дума, да сложат линкове и примери.

gemicha
Site Admin
Site Admin
Мнения: 2930
Регистриран: 20 ное 2003 22:20
Местоположение: USA

Re: Предифиниране на new

Мнение от gemicha » 05 юли 2012 23:56

Аз имам опит с това. Съвета ми е: Не си губи времето с това :) Напиши това, което си започнал и погледни къде имаш проблем. Ако имаш твърде много заделяне на памет от различни обекти първо се опитай да намалиш броя им. Едва след това погледни какви други възможности имаш.

Имаше преди време добра статия за работа с паметта в игра. Първото правило е да не заделяш или освобождаваш памет в цикъла, който чертае. Основното заделяне/освобождаваш на памет трябва да става когато ново ниво се зарежда или когато играта тръгва. Почти винаги може да се справиш с предефиниране. Примерно в Quake не може да имаш повече от X обекта защото има статично зададен размер на масива и това а максимума на активни обекти. Ако дадеш повече информация ще се опитам да ти кажа как аз бих го направил.

Потребителски аватар
themean
Power User
Power User
Мнения: 871
Регистриран: 02 дек 2010 22:51

Re: Предифиниране на new

Мнение от themean » 06 юли 2012 00:20

Въпросът ми не е свързан с разработване на игра, а по-скоро с любопитство.Бих искал да съм запознат с почти всички възможности, за да ми е по-лесно да избирам най-доброто решение, когато възникне проблем

Потребителски аватар
KosSiO
Power User
Power User
Мнения: 317
Регистриран: 20 окт 2008 19:29
Местоположение: Targovishte,Sofia

Re: Предифиниране на new

Мнение от KosSiO » 06 юли 2012 12:41

Аз искам да попитам как се справяте с фрагментацията на memory pool-a?

Решението при мен е следното : когато се изтрие даден обект, да се добавя един log в който да казвам "ей там има свободно място ей толкова байта" и ако мястото отговаря на нуждите слагам обекта там;

Другото което го прочетох някъде, но хич не ми хареса : Пазя указателя на всяко заделяне на памет и имам функция defragmet, която подрежда pool-a и променя указателите.

Потребителски аватар
haho
Power User
Power User
Мнения: 999
Регистриран: 07 дек 2003 21:52
Местоположение: България
Контакти:

Re: Предифиниране на new

Мнение от haho » 06 юли 2012 13:28

KosSiO написа: Другото което го прочетох някъде, но хич не ми хареса : Пазя указателя на всяко заделяне на памет и имам функция defragmet, която подрежда pool-a и променя указателите.

То и на мен не ми харесва, но е едно от малкото работещи решения на проблема. Другите са още по-тегави

Потребителски аватар
themean
Power User
Power User
Мнения: 871
Регистриран: 02 дек 2010 22:51

Re: Предифиниране на new

Мнение от themean » 06 юли 2012 13:35

Според мен варианта за дефрагментация е супер.Друга възможност е да имаш отделен пул за всеки тип обекти(такива с еднакъв размер) ама това не е много приложимо според мен и последното ми предложение е да погледнеш как е реализиран хипа на някоя операционна система

ikolev
модератор
модератор
Мнения: 1667
Регистриран: 20 ное 2003 22:39
Местоположение: София
Контакти:

Re: Предифиниране на new

Мнение от ikolev » 07 юли 2012 00:43

KosSiO написа:Аз искам да попитам как се справяте с фрагментацията на memory pool-a?
Никак.

Рядко би трябвало да имате нужда от такова нещо. Питайте Господ Строуструп. Според него повечето обекти е редно да се създават и унищожават в стека, не в динамичната памет. Дори да не успее човек да постигне такава нирвана и да му се наложи да държи много динамична памет, методите за управление на паметта са напреднали доста и е малко вероятно да победите добрия стар new/malloc откъм производителност.
За някои много динамични структури от данни (т.е. с многократно добавяне/изтриване), които имат фиксиран размер на елемента, може да е полезен някакъв тип pool allocator. И пак е по-добре първо да усетите нуждата, а после и да измерите ползата. Особено пък на РС. При машини с по-малко памет може би трябва да се внимава повече, най-вече като се предпочита статичното заемане на памет, както спомена Гемича че прави Quake.
А пък предефиниране на new/delete със сигурност е последното към което трябва да се поглежда.

zaphod
Power User
Power User
Мнения: 633
Регистриран: 01 мар 2004 21:46
Местоположение: София

Re: Предифиниране на new

Мнение от zaphod » 08 юли 2012 08:42

ако няма някакъв специален частен случай който да оправдава специален алокатор, твърдо съм против "подобряване" на алокацията. new/delete е много по-оптимално отколкото среден програмист може да постигне и всички "подобрения" влошават работата. понякога разбира се иамме специални случаи, когато някаква специфика позволява много по-бързо алокиране, например ако статистически очакваме много new без нито едно delete (например като строим дърво) то разни пулове носят значителна изгода. но това не е генерално подменяне на new, а си е вътрешен алокатор за дървото.

Потребителски аватар
themean
Power User
Power User
Мнения: 871
Регистриран: 02 дек 2010 22:51

Re: Предифиниране на new

Мнение от themean » 08 юли 2012 14:30

Аз разбирам ваще аргументи, но както казах питам от любопитство и ако някой има възможеност нека плесне код който демонстрира въпросното явление :)

Потребителски аватар
haho
Power User
Power User
Мнения: 999
Регистриран: 07 дек 2003 21:52
Местоположение: България
Контакти:

Re: Предифиниране на new

Мнение от haho » 09 юли 2012 10:45

ikolev написа: Никак.

Рядко би трябвало да имате нужда от такова нещо.
На конзолите винаги имаш много малко памет, през цялото време ти е заето 90-100% от нея, няма виртуална памет. От друга страна играта ти трябва да може да работи поне 12 часа без да забие. През това време ще алокираш и деалокираш много данни особено ако имаш стрийминг. На практика, е почти сигурно, че ще имаш проблем с дефрагментацията на паметта.

pdimov
gosu
gosu
Мнения: 871
Регистриран: 02 дек 2003 01:04

Re: Предифиниране на new

Мнение от pdimov » 09 юли 2012 18:53

haho написа:На конзолите винаги имаш много малко памет, през цялото време ти е заето 90-100% от нея, няма виртуална памет. От друга страна играта ти трябва да може да работи поне 12 часа без да забие. През това време ще алокираш и деалокираш много данни особено ако имаш стрийминг. На практика, е почти сигурно, че ще имаш проблем с дефрагментацията на паметта.
А как решаваш проблема?

Потребителски аватар
haho
Power User
Power User
Мнения: 999
Регистриран: 07 дек 2003 21:52
Местоположение: България
Контакти:

Re: Предифиниране на new

Мнение от haho » 09 юли 2012 22:54

pdimov написа:А как решаваш проблема?
За сега никак, защото играта ни заема 65-70% от паметта и няма много големи алокации дето да се "заклещят".
За вбъдеще бих направил базов клас с предефинирани new и delete и всичко да се достъпва през двойни указатели и когато има време да се дефрагментира. Тъкмо да те питам, ти какъв тип умни указатели или нещо друго би препоръчал за подобен достъп?

Потребителски аватар
themean
Power User
Power User
Мнения: 871
Регистриран: 02 дек 2010 22:51

Re: Предифиниране на new

Мнение от themean » 09 юли 2012 23:47

Не съм много наясно с нещата ама, но ми се върти в главата следната идея и бих искал да питам дали изглежда правдоподобна.
Човек заделя някакво парче памет(в случая на конзола цялата налична) и я дели на клъстери за големи, средни и малки обекти(ако иска и на повече парчета) като клъстерите са подредени по големина от ляво на дясно(за пример) в паметта.Идеята е следната:
Ако си запълнил клъстера с големи елементи и искаш да добавиш още един (от дясно) ще трябва да изкопираш няколко от елементите(1,2 или повече от най-левите) на следващия клъстер и да ги преместиш най в дясно за да можеш да разшириш нужния ти клъстер, ако нямаш място да преместиш елементите на по-малкия клъстер в най-дясно то повтаряш същото действие за следващия.Ако минеш през всички клъстери и не ти стига памет то значи наистина не ти стига и трябва да се изплюе грешка или да се освободи такава.
Това би трябвало да работи супер когата имаш достатъчно памет(което е нормално :)), когато няма извършва допълнителни копирания, но премахва нуждата от динамично фрагментиране и алгоритми които да изчисляват кога да го прави
Ако някога стигно до реализация на мемори пул мисля да го направя по този начи.

BIGBUGEX
Regular User
Regular User
Мнения: 77
Регистриран: 29 мар 2004 00:42
Местоположение: Nqkyde

Re: Предифиниране на new

Мнение от BIGBUGEX » 10 юли 2012 01:20

По яко от двойни указатели е въобще да не се налага фрагментиране. Фрагментирани масиви и странициращо дърво подобно на хардуерното в процесора. Чисто теоретично звучи добре. Да кажем списъци от масиви с фиксиран размер в зависимост от типа, като за начало. Тука изгъзиците с итератори от стл биха помогнали. Ако имам подобен проблем няма да имам свян да го проуча тоя вариант.

Потребителски аватар
themean
Power User
Power User
Мнения: 871
Регистриран: 02 дек 2010 22:51

Re: Предифиниране на new

Мнение от themean » 10 юли 2012 10:02

themean написа:Не съм много наясно с нещата ама, но ми се върти в главата следната идея и бих искал да питам дали изглежда правдоподобна.
Човек заделя някакво парче памет(в случая на конзола цялата налична) и я дели на клъстери за големи, средни и малки обекти(ако иска и на повече парчета) като клъстерите са подредени по големина от ляво на дясно(за пример) в паметта.Идеята е следната:
Ако си запълнил клъстера с големи елементи и искаш да добавиш още един (от дясно) ще трябва да изкопираш няколко от елементите(1,2 или повече от най-левите) на следващия клъстер и да ги преместиш най в дясно за да можеш да разшириш нужния ти клъстер, ако нямаш място да преместиш елементите на по-малкия клъстер в най-дясно то повтаряш същото действие за следващия.Ако минеш през всички клъстери и не ти стига памет то значи наистина не ти стига и трябва да се изплюе грешка или да се освободи такава.
Това би трябвало да работи супер когата имаш достатъчно памет(което е нормално :)), когато няма извършва допълнителни копирания, но премахва нуждата от динамично фрагментиране и алгоритми които да изчисляват кога да го прави
Ако някога стигно до реализация на мемори пул мисля да го направя по този начи.
Относно написаното от мен искам да кажа, че не е добре обмислено и пак се налага дефрагментиране.
Когато го писах ми изглеждаше добре защото си го представях само в случая на добавяне на обекти но не и на махане.
Когато махаш обект неговото място остава празно тук възможните варианти според мен са следните(в случая когато обекта се намира между други от същия клъстер в противен случай няма проблем):
1) Записва се че там има парче памет с еди какъв си размер и следващия път при заявка за добавяне на обект със същия размер се бута там.
2) Когато клъстер достигне някаква степен на фрагментация и 1) не е изпълнимо се дефрагментира частично (приплъзват се лементи към средата от ляво на дясно или обратно в зависомост кое ще отнеме по-малко работа) и тогава се добавя ония елемент(от ляво или от дясно в зависимост от къде е освободено памет)
3)Дефрагментация на бекграунд, за съжаление това изисква мютекси към всеки поинтер сочещ към обект от въпросния пул

pdimov
gosu
gosu
Мнения: 871
Регистриран: 02 дек 2003 01:04

Re: Предифиниране на new

Мнение от pdimov » 10 юли 2012 11:06

haho написа:За вбъдеще бих направил базов клас с предефинирани new и delete и всичко да се достъпва през двойни указатели и когато има време да се дефрагментира. Тъкмо да те питам, ти какъв тип умни указатели или нещо друго би препоръчал за подобен достъп?
В единствения случай, в който съм срещал фрагментиране, проблемът не беше от това, че има разпръснати живи обекти из паметта, а защото free (на MSVC) не успяваше да си обедини свободните блокове. Грубо казано, цикъл на malloc 9 Mb, malloc 5 Mb, после по някое време free на всичко това едно по едно, и в един момент malloc на 9 Mb започва да не иска да работи, въпреки че паметта е почти изцяло свободна. Двойни указатели в случая не биха ми помогнали. Аз просто сложих един dlmalloc и нещата се оправиха. (Преди това пробвах с включване на "low fragmentation heap" на Windows, нещата се подобриха леко, но не колкото ми се искаше.)

Фрагментацията, причинена от много живи малки алокации, е различно нещо и се решава най-лесно с pool за обектите (особено ако всичките обекти са с еднакъв размер) или пък с грубо директно държане на обектите във std::vector (при което е добре да се уцели аргумента на reserve така, че да се мине сертификация :-) ) или std::deque. Повечето системни алокатори си имат вграден "small object heap" вече, така че това рядко се налага в наши дни, като че ли. Не знам как е по конзолите. Би следвало поради малкото памет да са поработили върху алокатора, но знаеш ли ги.

Отговори