Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2008.10.05;
Скачать: [xml.tar.bz2];

Вниз

Куча или стек ?   Найти похожие ветки 

 
DevilDevil ©   (2008-08-09 12:14) [0]

Доброе время суток, уважаемые форумчане.

Есть задача, в которой необходимо заюзать неопределённое количество памяти с минимальной время-потерей.

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

Вопрос сформулирован примерно следйющим образом...
Где граница (размер в байтах), превышая которую лучше (быстрее, безопаснее, ...) отхватить кусок из кучи ?


 
Sergey Masloff   (2008-08-09 12:21) [1]

Что значит отхватить?


 
Zeqfreed ©   (2008-08-09 12:33) [2]

> Где граница (размер в байтах), превышая которую лучше (быстрее,
>  безопаснее, ...) отхватить кусок из кучи ?

stacksize?


 
DevilDevil ©   (2008-08-09 12:33) [3]

function OthvatitStek(Size: integer): pointer;
asm
 // eax := esp - eax - 1024
 add eax, 1024
 neg eax
 add eax, esp
end;

function OnvatitKuchu(Size: integer): pointer;
begin
 GetMem(Result, Size);
end;


 
DevilDevil ©   (2008-08-09 12:40) [4]

> Zeqfreed ©   (09.08.08 12:33) [2]

что есть "stacksize" ?

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

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


 
Loginov Dmitry ©   (2008-08-09 13:04) [5]

> В общем, нужен человек, который про стек знает многое...


А Рихтер не подходит?
:)


 
DevilDevil ©   (2008-08-09 13:09) [6]

рихтер - это долго.


 
Sergey Masloff   (2008-08-09 14:02) [7]

>рихтер - это долго.
Зато навсегда.

>DevilDevil ©   (09.08.08 12:33) [3]
Ну так-то быстрее. Естественно двинуть указатель и все. Но кто мешает взять в куче сразу большую область и точно также двигать по ней указатели?


 
DevilDevil ©   (2008-08-09 14:21) [8]

> Sergey Masloff   (09.08.08 14:02) [7]
> Зато навсегда.


Если не заблуждаюсь, тема не о пользе прочтения рихтера.

> Но кто мешает взять в куче сразу большую область и точно также
> двигать по ней указатели?


Ну так-то проще - отписать ересь какую-нибудь вместо ответа на чётко сформулированный вопрос.


 
Sergey Masloff   (2008-08-09 15:02) [9]

DevilDevil ©   (09.08.08 14:21) [8]
Терминология на вашей совести.
Никакой четкости в вопросе нет.
Я описал вариант работы с кучей который не будет отличаться от работы со стеком. То есть никакой границы нет. Как в стеке никто (почти) не будет следить за безопасностью так и в куче. Скорость доступа к стеку и к куче может быть практически одинаковой.


 
DevilDevil ©   (2008-08-09 15:06) [10]

вопрос открыт


 
VirEx ©   (2008-08-09 15:16) [11]

для резервации больших объемов памяти - куча, для малых - стек
вопрос закрыт


 
Zeqfreed ©   (2008-08-09 15:17) [12]

Есть вариант, что оптимизировать надо в другом месте.


 
DevilDevil ©   (2008-08-09 15:18) [13]

> для резервации больших объемов памяти - куча, для малых
> - стеквопрос закрыт


золотые слова!!!
в том то и вопрос: "большой объём" - это сколько байт ?


 
oxffff ©   (2008-08-09 15:22) [14]


> DevilDevil ©   (09.08.08 15:06) [10]
> вопрос открыт


Если ты можешь гарантировать что страницы стека будут гарантировано подгружены заранее,т.е. организовать unpageable pool, то стек естественно более предпочтительней поскольку вся операция Alloc это
sub esp, Size.
Однако в противном случае при работе со стеком тебе придется выделять постранично генерируя исключение процессора для выделения физической страницы. Что естественно очень накладно. Тогда предпочтение естественно куча.

НО!!! Я бы выбрал другой вариант

Никто не мешает организовать тебе свой менеджер памяти.  VirtualAlloc тебе в помощь.


 
DevilDevil ©   (2008-08-09 15:34) [15]

> oxffff ©   (09.08.08 15:22) [14]

для объёмов в 4, 10 или 100 байт свой или Delphi-йский менеджер памяти - дело относительно накладное. А вот пару мегабайт уже надо бы в куче делать. Вот и вопрос: где же эта граница ?

я не могу гарантировать, что страницы стека будут гарантированно подгружены.


 
oxffff ©   (2008-08-09 15:36) [16]


> дело относительно накладное.


Относительно чего?


> где же эта граница ?


Граница у автора.


 
VirEx ©   (2008-08-09 15:38) [17]


>  [15] DevilDevil ©   (09.08.08 15:34)
> Вот и вопрос: где же эта граница
> ?

так проверь свободную физическую память и выбирай


 
DevilDevil ©   (2008-08-09 15:42) [18]

if (Size > SOME_CONST) then
 P := GetMem(Size)
else
asm
 push eax

 lea eax, esp-100
 dec eax, Size
 mov P, eax

 pop eax
end;

if (Size > SOME_CONST) then
 FreeMem(P);


Вот такой вариант мне нравится намного больше, чем реализация собственного менеджера памяти и заюзывания VirtualAlloc


 
DevilDevil ©   (2008-08-09 15:43) [19]

вопрос: чему равна SOME_CONST ?

> VirEx ©   (09.08.08 15:38) [17]
> так проверь свободную физическую память и выбирай


уточни, пожалуйста.


 
oxffff ©   (2008-08-09 15:48) [20]


> DevilDevil ©   (09.08.08 15:42) [18]


У тебя код не правильный.


 
DevilDevil ©   (2008-08-09 15:52) [21]

> oxffff ©   (09.08.08 15:48) [20]
опечатки в коде не имеют отношения к обсуждаемому вопросу.


 
oxffff ©   (2008-08-09 16:01) [22]


> DevilDevil ©   (09.08.08 15:52) [21]


Это не опечатки.
Почему не изменяется ESP?


 
DevilDevil ©   (2008-08-09 16:20) [23]

> oxffff ©   (09.08.08 16:01) [22]
> Почему не изменяется ESP?


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


 
oxffff ©   (2008-08-09 16:45) [24]


> DevilDevil ©   (09.08.08 16:20) [23]


Явно ты можешь их не вызывать, за тебя это может сделать компилятор.
Однако представь, что будет с твоими данными, если возникнет исключение.


 
Юрий Зотов ©   (2008-08-10 02:26) [25]

> DevilDevil ©   (09.08.08 15:18) [13]

> "большой объём" - это сколько байт?

Семь.


 
Dimka Maslov ©   (2008-08-10 11:00) [26]

Для единичного зохавывания блока памяти разницы никакой нет, стек или куча. Если зохавывание выполняется в цикле - есть. Но если блок достаточно большой, то для его обработки потребуется куда как большее время нежели на выделение. Отсюда мораль - а не вынести ли выделение за пределы цикла, используя выделенный блок по новой в каждой итерации. Тогда "потери времени" станут незначительными.


 
Rouse_ ©   (2008-08-10 12:51) [27]


> DevilDevil ©

ИМХО ты не стой стороны подходишь к оптимизации. К тому-же при использовании стека ты имеешь большой, даже огромный шанс, исчерпать его лимит при рекурссионном алгоритме. Я бы делал другим образом - выделял бы единовременно необходимый блок памяти с запасом и на него навернул бы некий механизм, реализующий одобную работу с размещенными данными.


 
Рамиль ©   (2008-08-11 08:32) [28]

SOME_CONST = 42 :)


 
Сергей М. ©   (2008-08-11 08:38) [29]


> DevilDevil ©   (09.08.08 15:34) [15]
> для объёмов в 4, 10 или 100 байт свой или Delphi-йский менеджер
> памяти - дело относительно накладное


Штатный ВММ оптимизирован как раз для работы с блоками малого размера,  кратными размеру указателя.

FastMM-менеджер как альтернатива ВММ ощутимо лучшим образом оптимизирует операции сборки мусора.


 
Asteroid   (2008-08-11 13:11) [30]

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


 
han_malign ©   (2008-08-11 15:10) [31]


> обусловимся, что подобная махинация со стеком действует
> исключительно в этой функции, вызовов других функций внутри
> этой не производится.

- низя, можешь промахнуться мимо GUARD страницы стека, с непредсказуемым результатом(точнее, с вполне предсказуемым - как пишет Рихтер, на AV система молча прибьет процесс, даже Stack overflow на прощание не скажет)... Компилятор Delphi для выделения больших буферов на стеке делает цикл <push DWORD; push DWORD;>...


 
DiamondShark ©   (2008-08-11 15:34) [32]


> в том то и вопрос: "большой объём" - это сколько байт ?

Это больше, чем размер примитивных типов.


 
Anatoly Podgoretsky ©   (2008-08-11 15:45) [33]

> DiamondShark  (11.08.2008 15:34:32)  [32]

Большой размер - это когда в тару не помещается, без знания размера тары вопрос не корректен.


 
oxffff ©   (2008-08-11 15:57) [34]


> han_malign ©   (11.08.08 15:10) [31]


Есть улучшенная реализация fastStackAlloc в одном из стандартных модулей. Идея в sub esp до страницы-4 , далее push, далее опять sub,4092, push итеративно до нужного размера.


 
DevilDevil ©   (2008-08-11 16:36) [35]

> han_malign ©   (11.08.08 15:10) [31]

т.е.: описанный мной метод действует только в рамках текущей страницы? ну или самому в нужное время вызывать push.

> oxffff ©   (11.08.08 15:57) [34]
у меня Delphi 6, fastStackAlloc не найден... но зато найден StackAlloc/StackFree в гребенях, в implementation секции модуля grids.pas:


{ StackAlloc allocates a "small" block of memory from the stack by
 decrementing SP.  This provides the allocation speed of a local variable,
 but the runtime size flexibility of heap allocated memory.  }
function StackAlloc(Size: Integer): Pointer; register;
asm
 POP   ECX          { return address }
 MOV   EDX, ESP
 ADD   EAX, 3
 AND   EAX, not 3   // round up to keep ESP dword aligned
 CMP   EAX, 4092
 JLE   @@2
@@1:
 SUB   ESP, 4092
 PUSH  EAX          { make sure we touch guard page, to grow stack }
 SUB   EAX, 4096
 JNS   @@1
 ADD   EAX, 4096
@@2:
 SUB   ESP, EAX
 MOV   EAX, ESP     { function result = low memory address of block }
 PUSH  EDX          { save original SP, for cleanup }
 MOV   EDX, ESP
 SUB   EDX, 4
 PUSH  EDX          { save current SP, for sanity check  (sp = [sp]) }
 PUSH  ECX          { return to caller }
end;

{ StackFree pops the memory allocated by StackAlloc off the stack.
- Calling StackFree is optional - SP will be restored when the calling routine
 exits, but it"s a good idea to free the stack allocated memory ASAP anyway.
- StackFree must be called in the same stack context as StackAlloc - not in
 a subroutine or finally block.
- Multiple StackFree calls must occur in reverse order of their corresponding
 StackAlloc calls.
- Built-in sanity checks guarantee that an improper call to StackFree will not
 corrupt the stack. Worst case is that the stack block is not released until
 the calling routine exits. }
procedure StackFree(P: Pointer); register;
asm
 POP   ECX                     { return address }
 MOV   EDX, DWORD PTR [ESP]
 SUB   EAX, 8
 CMP   EDX, ESP                { sanity check #1 (SP = [SP]) }
 JNE   @@1
 CMP   EDX, EAX                { sanity check #2 (P = this stack block) }
 JNE   @@1
 MOV   ESP, DWORD PTR [ESP+4]  { restore previous SP  }
@@1:
 PUSH  ECX                     { return to caller }
end;


Симпатичные функции, наверное ими и воспользуюсь.
Но напрашивается 2 вопроса:

1) до каких пор (до какого размера) я могу расширять стек.
2) может ли кто пролить свет на "слабые места" менеджера памяти... иначе говоря, за счёт чего происходят время-потери ?


 
DevilDevil ©   (2008-08-11 16:53) [36]

одного не могу понять...

вот есть какой-то код... Ага, сейчас надо (как минимум) запушить eax, edx и ecx, а после вызова функции восстановить eax, edx и ecx... но не тут то было - esp уже изменил своё местоположение.

Не нахожу место в коде, благодаря которому ошибок юзания стека не произошло бы. Ткните носом плиз.


 
DevilDevil ©   (2008-08-11 19:07) [37]

Скажите, насколько это опасно ???

В моём случае фишка со StackAlloc сработала без ошибок. Но что если компилятор запушит регистры перед вызовом функции, а после - постарается вернуть из стека.

Я провёл тест:

   //P := StackAlloc(BufferingSize);
   asm
     push eax
     mov PUSH_DATA1, eax

       mov eax, BufferingSize
       call StackAlloc
       mov P, eax

     pop eax
     mov PUSH_DATA2, eax
   end;


И оказалось, что eax до вызова совсем не равен eax-у после. Кто-нибудь может объяснить, может разработчики Delphi изначально уверены, что перед вызовом такой функции ни один из регистров пушиться не будет ?


 
oxffff ©   (2008-08-11 21:02) [38]


> DevilDevil ©   (11.08.08 16:36) [35]


Я про них и говорил.



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2008.10.05;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.007 c
4-1197319990
ДжонС
2007-12-10 23:53
2008.10.05
JPG загрузить


15-1219000113
Andy BitOff
2008-08-17 23:08
2008.10.05
Компонент реализующий RAMDisk.


2-1219941100
Greebanyi 2bus
2008-08-28 20:31
2008.10.05
Clock


3-1207291974
Альберт
2008-04-04 10:52
2008.10.05
Поиск дубликатов


2-1219594068
TStas
2008-08-24 20:07
2008.10.05
Глюк дельфей в консольном приложении





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский