Форум: "Прочее";
Текущий архив: 2006.11.19;
Скачать: [xml.tar.bz2];
ВнизДинамическое выделение памяти на стеке Найти похожие ветки
← →
Alex Konshin © (2006-10-28 11:38) [0]Я тут велосипед избрел...
Вроде как научился безопасно и быстро выделять память на стеке.
Смотрел на полученный код и тестировал разные ситуации, вроде подвохов не обнаружил. Может вы чего нароете?
Для чего это нужно? Удобно портировать C/C++ код в котором место под небольшие временые массивы с неконстантным размером запросто выделяется на стеке простым объявлением, и потому очень часто используется. Брать-отдавать память - медлено. Вот я и придумал вроде как приемлемый способ это сделать.
Как это работает? Во-первых, я надеюсь, что это действительно работает:).
Конструкция try...finally создает frame на стеке. При выходе по Exit или при исключении этот фрейм откатывается и указательстека восстанавливается автоматом. Поэтому нам нужно позаботится только об восстановлении указателя стека при нормальном входе из try...finally. Естественно, выделять память нужно кусками, кратными 4. Собственно, вот и вся хитрость.
procedure NN_ModInv( a, b, c: PDigits; digits : LongWord );
var
q, t1, t3, u1, u3, v1, v3, w : PDigits;
old_esp : Pointer;
begin
// Do something
...
try
// Allocate temp space on stack
asm
mov old_esp,esp
mov eax,digits
shl eax,2
sub esp,eax
mov q,esp
sub esp,eax
mov t1,esp
sub esp,eax
mov t3,esp
sub esp,eax
mov u1,esp
sub esp,eax
mov u3,esp
sub esp,eax
mov v1,esp
sub esp,eax
mov v3,esp
sub esp,eax
sub esp,eax
mov w,esp
end;
// Do something
...
...
asm
mov esp,old_esp
end;
finally
// Restore stack pointer.
// try...finally creates stack frame.
end;
end;
← →
Alex Konshin © (2006-10-28 11:56) [1]А, забыл сказать, что если используется Exit, то перед ним указатель стека тоже нужно восстанавливать ( asm mov esp,old_esp end; ).
Ну и понятно, что все это имеет смысл, когда скорость выполнения очень критична. В другом случае можно найти способ и по-проще :)
← →
Суслик © (2006-10-28 12:39) [2]
> Alex Konshin © (28.10.06 11:56) [1]
глупый вопрос можно?
ты уверен, что оптимизатор не заоптимизирует пустой try-finally.
такой гарантии имхо никто дать не может.
← →
Суслик © (2006-10-28 12:40) [3]вернее пустой finally end.
← →
Суслик © (2006-10-28 12:47) [4]я, конечно, не специалист, но почему бы непереместить восстановление стека в finally end?
← →
Ketmar © (2006-10-28 14:16) [5]>[0] Alex Konshin(c) 28-Oct-2006, 11:38
бр-р-р... пугаешь спросонья. %-) способ вполне. только надо добавить для копипастеров, что если большие объёмы -- не прокатит. надо будет последовательно странички "трогать". %-)
← →
Суслик © (2006-10-28 14:28) [6]господа, просветите, пожалуйста, непросвещенных про странички - ну так, хотя бы в общем.:)
← →
Ketmar © (2006-10-28 14:54) [7]>[6] Суслик(c) 28-Oct-2006, 14:28
>господа, просветите, пожалуйста, непросвещенных про
>странички - ну так, хотя бы в общем.:)
память для стека выделяется не сразу толпой, а постранично (кажись, по 4 кб; может, в новых системах по 64 или около того -- не в курсе). на страничку, которая идёт перед рабочей, ставится флажок "GUARD". если к ней обращаются, возникает исключение. система его ловит, и выделяет ещё для стека кусочек. и так далее. но! если выделить, например, 16 килобайт за раз, есть шанс попасть мимо "охраняемой" странички. и поймать исключение, на которое система уже не среагирует. т.е. банальный AV. поэтому надо выделять по 4 кила, и каждый четырёхкилобайтный кусочек "трогать" (т.е. читать оттуда что-то, например). этим ты гарантируешь работоспособность своей программы на любой вменяемой системе.
← →
iZEN © (2006-10-28 15:11) [8]В Java 6.0 (Mustang) объекты с ограниченной обласьтю видимости (внутри методов) инстанцируются на стэке. Это повышает производительность в разы. ;)
← →
wicked © (2006-10-28 16:03) [9]
> В Java 6.0 (Mustang) объекты с ограниченной обласьтю видимости
> (внутри методов) инстанцируются на стэке.
наконец то, дошли...
еще бы счетчик ссылок на обьекты в куче - и gc бы ловил только циклически ссылающиеся обьекты - еще существенный прирост производительности...
← →
Alex Konshin © (2006-10-28 16:19) [10]Прежде чем гадать, просто посмотри код.
> Суслик © (28.10.06 12:47) [4]
> я, конечно, не специалист, но почему бы непереместить восстановление
> стека в finally end?
То, что внутри finally...end оформляется как процедурка, которая вызывается при откате фрейма. Так что там уж точно не нужно трогать стек.
← →
default © (2006-10-28 16:22) [11]кстати, можно создать класс управляющий стеком, то есть предоставлять высокоуровневое пользование стека
надо только подумать есть ли в этом смысл
вот пример
TStackManager = class
procedure NextStackAlloc(var P: Pointer; countDWords: LongWord);
end;
...
procedure TStackManager.NextStackAlloc(var P: Pointer; countDWords: LongWord);
asm
shl countDWords, 2
sub countDWords, 4
add esp, countDWords
mov [P], esp
jmp [esp+countDWords]
end;
NextStackAlloc выделят указанное число двойных слов в стеке и записывает адрес на него в P
идея проста - получаем
UserStackDWord
....
UserStackDWord
UserStackDWord
RET ADDRESS
далее JMP-ом прыгаем на RET ADRESS тем самым после выполения метода мы получаем кусок стека и переменную указывающую на него и ничего другого
← →
Alex Konshin © (2006-10-28 16:27) [12]Хитрость использования вроде бы ненужного try...finally в том, что создается фрейм, что гарантирует правильный откат стека при исключениях и Exit.
← →
default © (2006-10-28 16:31) [13]RET ADDRESS - это тоже часть юзерской памяти стека
не add esp, countDWords, а
sub esp, countDWords конечно
← →
Alex Konshin © (2006-10-28 16:31) [14]> default © (28.10.06 16:22) [11]
Да выделить-то не проблема. Я в ассемблере это частенько делаю.
Проблема была не обломиться при исключениях.
← →
default © (2006-10-28 16:43) [15]Alex Konshin © (28.10.06 16:31) [14]
всё-таки может лучше классом оформить - добавить ещё в него метод для освобождения всей выделенной памяти
тогда всё низкоуровневое будет скрыто
а то при каждой портации код будет пестреть asm кодом что выглядит не очень:)
← →
Ketmar © (2006-10-28 17:20) [16]>[14] Alex Konshin(c) 28-Oct-2006, 16:31
>Проблема была не обломиться при исключениях.
в конце делаем принудительный raise.
а все вместе заключаем вtry try except finally
.
смотрим и наслаждаемся "ужосом". %-))
← →
iZEN © (2006-10-28 18:20) [17]
> wicked © (28.10.06 16:03) [9]
> > В Java 6.0 (Mustang) объекты с ограниченной обласьтю видимости
> > (внутри методов) инстанцируются на стэке.
>
> наконец то, дошли...
>
> еще бы счетчик ссылок на обьекты в куче - и gc бы ловил
> только циклически ссылающиеся обьекты - еще существенный
> прирост производительности...
У GC HotSpot JVM с рождения нету никаких счётчиков (в отличие от OLE/COM и VB).
Обычные (односторонние) и циклические (образующие кольцо) ссылки обрабатываются по стратегии "поколений".
← →
Суслик © (2006-10-28 18:56) [18]
> Ketmar © (28.10.06 14:54) [7]
спасибо
> Alex Konshin © (28.10.06 16:19) [10]
> Прежде чем гадать, просто посмотри код.
Это ты мне? Я, действительно, не очень знаю как там все устроено, но знаю одно - потимизатор штука коварная.
Ты все-таки задумайтся о том, что дельфи волен оптимизировать пустой finally end. Он не подписывался на то, что оптимизировать не это не будет. Хотя я могу быть и неправ? Но я в доках этого не видел.
← →
default © (2006-10-28 19:50) [19]
TStackManager = class
private
FCountBytes: LongWord;
public
procedure NextStackAlloc(var P: Pointer; countDWords: LongWord);
procedure Clear;
end;
...
procedure TStackManager.NextStackAlloc(var P: Pointer; countDWords: LongWord);
asm
shl countDWords, 2
add Self.FCountBytes, countDWords
sub countDWords, 4
sub esp, countDWords
mov [P], esp
jmp [esp+countDWords]
end;
procedure TStackManager.Clear;
asm
pop ecx
add esp, Self.FCountBytes
jmp ecx
end;
вот пример менеджера стека
можете пользовать кому интересно
← →
jack128 © (2006-10-28 20:07) [20]Alex Konshin © (28.10.06 11:38)
Динамическое выделение памяти на стеке
unit Grids;
function StackAlloc(Size: Integer): Pointer; register;
procedure StackFree(P: Pointer); register;
← →
Суслик © (2006-10-28 20:19) [21]
> jack128 © (28.10.06 20:07) [20]
чисто теоретический вопрос - а кто восстанавливает SP в случае исключения в методе TCustomGrid.Paint?
← →
jack128 © (2006-10-28 20:25) [22]Суслик © (28.10.06 20:19) [21]
а фиг его знает.. Может борланды подумали, что исключения там настолько маловероятно, что на них не нужно закладываться..
← →
Суслик © (2006-10-28 20:28) [23]
> jack128 © (28.10.06 20:25) [22]
я когда писал свой грид по мотивам grids (просто взял борландовый грид и отрезал лишнее - для меня - потом добавил требуемое), то это место еще тогда вопрос вызвало. но тогда я на это забил.
← →
Alex Konshin © (2006-10-29 00:31) [24]> jack128 © (28.10.06 20:07) [20]
> Alex Konshin © (28.10.06 11:38)
> Динамическое выделение памяти на стеке
>
> unit Grids;
>
> function StackAlloc(Size: Integer): Pointer; register;
> procedure StackFree(P: Pointer); register;
Я об этом, естественно, знал. Я же в свое время написал ArrayGrids и потому Grids знал почти наизусть. И есть у меня сомнения, что это будет корректно работать c Exit, точнее, я знаю, что будет работать некорректно - смотри System._TryFinallyExit. Эта процедурка отрабатывает по Exit внутри try...finally. Как можно заметить, она явно ожидает стекфрейм сразу за адресом возврата.
Я знаю, что выделять память на стеке можно. Собственно, нового в моем фрагменте только то, как сделать это безопасно для исключений и Exit.
← →
Alex Konshin © (2006-10-29 00:34) [25]
> default © (28.10.06 19:50) [19]
>
>
> TStackManager = class
> private
> FCountBytes: LongWord;
> public
> procedure NextStackAlloc(var P: Pointer; countDWords:
> LongWord);
> procedure Clear;
> end;
>
> ...
>
> procedure TStackManager.NextStackAlloc(var P: Pointer; countDWords:
> LongWord);
> asm
> shl countDWords, 2
> add Self.FCountBytes, countDWords
> sub countDWords, 4
> sub esp, countDWords
> mov [P], esp
> jmp [esp+countDWords]
> end;
>
> procedure TStackManager.Clear;
> asm
> pop ecx
> add esp, Self.FCountBytes
> jmp ecx
> end;
>
>
> вот пример менеджера стека
> можете пользовать кому интересно
← →
Суслик © (2006-10-29 00:42) [26]
> Alex Konshin © (29.10.06 00:31) [24]
> Я же в свое время написал
> ArrayGrids и потому Grids знал почти наизусть.
ОФФ
Если так, то скажи, пожалуйста, что делает
procedure TInplaceEdit.Invalidate;
var
Cur: TRect;
begin
ValidateRect(Handle, nil);
InvalidateRect(Handle, nil, True);
Windows.GetClientRect(Handle, Cur);
MapWindowPoints(Handle, Grid.Handle, Cur, 2);
ValidateRect(Grid.Handle, @Cur);
InvalidateRect(Grid.Handle, @Cur, False);
end;
Не по семантике, которая описана в хелпе, а по строчкам.
Конкретный вопрос
Зачем первой строкой
ValidateRect(Handle, nil);
А второй
InvalidateRect(Handle, nil, True);
← →
Alex Konshin © (2006-10-29 00:59) [27]Извиняюсь, случайно отправил.
Наворачивать тут класс уж явно не к месту. Создание объекта - это уже обращение к менеджеру памяти. А если уж всеравно обращаемся, то тогда и можно и временую память брать по GetMem. Ну да, можно, конечно, объект завести один и потом им одним пользоваться, но тогда нужно следить за вложенными вызывами.
Теоретически, я думаю, можно подумать в сторону методов в описании Record (вроде как это теперь можно в BDS2006).
Тогда можно будет написать что-то типа:
type
TDynStackManager = record
Size : LongWord;
old_esp : pointer;
function Allocate( Size : LongWord ) : Pointer;
procedure Free;
end;
procedure Test();
var
stackManager : TDynStackManager;
temp : Pointer;
begin
try
temp := stackManager.Allocate(10);
// Do something
stackManager.Free;
finally
end;
end;
Вообще я так смотрю, что они довольно много добавили в язык в BDS2006.
Кстати, мое исследование показывает, что теоретически не сложно добавить в язык и динамическое массивы на стеке. Правда, этого мы уже не увидим.
← →
Alex Konshin © (2006-10-29 01:04) [28]> Суслик © (29.10.06 00:42) [26]
>
> > Alex Konshin © (29.10.06 00:31) [24]
> > Я же в свое время написал
> > ArrayGrids и потому Grids знал почти наизусть.
Ну, тут прямо слово не скажи :) Говорю же что знал. Но разобраться, если надо, смогу быстро. Извини, но не сейчас и не в этой ветке, пож-ста.
← →
Суслик © (2006-10-29 01:05) [29]
> Вообще я так смотрю, что они довольно много добавили в язык
> в BDS2006.
ошибок пока только очень много. особенно в записях с методами.
> Правда, этого мы уже не увидим.
почему?
--------
они хотят в язык еще очень много добавить - например неявные инициализаторы и файнализаторы для записей (аналоги существующих сейчас system._initializerecord и system._finalizerecord).
Вот жизнь начнется - я думаю, что появятся разработки GC для DelphiWin32 на основе указанной возможности :)
← →
Суслик © (2006-10-29 01:06) [30]
> Alex Konshin © (29.10.06 01:04) [28]
> > Суслик © (29.10.06 00:42) [26]
> Ну, тут прямо слово не скажи :) Говорю же что знал. Но разобраться,
> если надо, смогу быстро. Извини, но не сейчас и не в этой
> ветке, пож-ста.
хорошо. завтра в winapi задам, т.к. вопрос к winapi в основном относится.
буду рад если кто-нить ответит ибо я не понимаю.
← →
default © (2006-10-29 01:25) [31]Alex Konshin © (29.10.06 00:59) [27]
это понятно, класс это так - если понадобятся ещё какие фичи для работы со стеком
а так что избежать асмовых инструкций при каждой портации можно просто две подпрограммки написать и одну глобальную переменную заиметь для них
всё-таки лучше читаться код будет - особенно теми кого пугает асм
особенно если требуется расбрасывать аллокации по коду
не будем же мы писать 10 строчек на дельфи потом asm end десять строчек на дельфи - asm end; :)
← →
Alex Konshin © (2006-10-29 01:33) [32]> default © (29.10.06 01:25) [31]
> не будем же мы писать 10 строчек на дельфи потом asm end
> десять строчек на дельфи - asm end; :)
Собственно, я так сейчас и делаю. Для меня в этом проектике скорость принципиально важна - я с криптографией балуюсь.
Record будет лучше - он тут более к месту, т.к. он будет на стеке. Правда это сделать можно только в BDS.
Глобальную переменную нельзя - не будет реентерабельности.
← →
Суслик © (2006-10-29 01:40) [33]
> Правда это сделать можно только в BDS.
а просто рекорд и глобальная функция, работающая с record"ом?
← →
Alex Konshin © (2006-10-29 01:56) [34]> Суслик © (29.10.06 01:40) [33]
> > Правда это сделать можно только в BDS.
>
> а просто рекорд и глобальная функция, работающая с record"ом?
Это завсегда можно, но намного менее красиво (О, как сказал!) :)
← →
Суслик © (2006-10-29 02:06) [35]
> Alex Konshin © (29.10.06 01:56) [34]
Вообще BDS до устойчивой работы компилятора НЕ в демах, а в рабочих проектах в области НОВЫХ фишек еще далеко. С записями и их методами, действительно, много багов.
А вот перегрузка операторов работает отлично. Сам иногда поражаюсь - как можно наплодить столько багов в задаче, которая в первого взглада не видитсья сложной (методы в записях) и суметь сделать классно перегрузку операторов в тех же записях.
Такое ощущение, что там несколько неависимых команд работает :)
PS. Это я все к тому, что *пока* красота в записях еще не совсем красота.
← →
Ketmar © (2006-10-29 02:11) [36]>[35] Суслик(c) 29-Oct-2006, 02:06
>и суметь сделать классно перегрузку операторов
раскоментарили старый код, оставшийся от C++. %-)
← →
Суслик © (2006-10-29 02:15) [37]
> Ketmar © (29.10.06 02:11) [36]
возможно, т.к. она сделана действительно классно.
я ее мучал во все дыры.
иногда прослеживалось то, что компилятор делал до 100 операций прежде чем сложить мне две записи - находил цепочки неявных преобразований, приводивших к тому, что находилась запись, которая моглы выполнить сложение.
← →
Ketmar © (2006-10-29 02:19) [38]>[37] Суслик(c) 29-Oct-2006, 02:15
>иногда прослеживалось то, что компилятор делал до 100
>операций прежде чем сложить мне две записи - находил
>цепочки неявных преобразований, приводивших к тому, что
>находилась запись, которая моглы выполнить сложение.
я под столом. буквально. стул развалился. смеялся я сильно. я вообще к перегрузкам отношусь так же, как Вирт -- потому и смеялся.
← →
Суслик © (2006-10-29 02:29) [39]
> Ketmar © (29.10.06 02:19) [38]
смейся обратно.
как принимающий участие в qc.borland.com (в отличие от вас всех, любители поговорить) могу сказать, что я это делал исключительно в целях тестирования - заявленная фича должна работать независимо от уровня идиотизма программируещего.
← →
Ketmar © (2006-10-29 02:36) [40]>[39] Суслик(c) 29-Oct-2006, 02:29
>смейся обратно.
я опять не так выразился. я смеюсь не по поводу её работоспособности или нет. а по поводу самого факта её наличия. и вытекающих.
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2006.11.19;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.047 c