Модераторы: Се ля ви
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Стек и heap на современой машине, потери производительности с обычной памя 
V
    Опции темы
Sardar
Дата 14.7.2006, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 1
Всего: 317



Все знают что аллокации переменных на стеке быстрей чем в куче (heap memory), НО! откуда это пошло и так ли это сейчас? smile

Раньше push/pop'или простые значения, сейчас порой сложные обьекты. При создании обьекта на стеке просто поднимают выше значение регистра-указателя-на-верхушку-стека (SP), далее идёт инициализация "полей". При этом вся работа со стеком это увеличение/уменьшения SP, сама инициализация происходит обычными инструкциями по работе с памятью (не мнемоники имею в виду, физически те же инструкции) относительно SP. Плюсы подхода:
  • можно выделить точно требуемое количество байтов (слов) на стеке
  • о скорости поговорим чуть позже smile
Теперь память. И стек и куча находяться в памяти, перед использованием помещаються в кешь. Если по памяти гулять рандомно, то от кеша пользы мало, проц работает со скоростью FSB. Стек же принуждает находиться в одной странице кеша. Кстати именно из-за кеша опровергнем ранее верную теорию: циклы и вызов малых функций медленней чем просто полотно комманд, поэтому циклы разворачивали, а функции включали (inline) в код. На современных процах чем меньше требуеться подкачивать инфу с общей памяти в кешь, чем больше кешь реюзаеться (циклы, малые функции), тем быстрее прога! smile

Вторая проблема памяти это её выделение операционной системой. Физически нельзя выделить один int (да, иногда пишут new int smile ) в памяти, по любому будет выделен целый блок размером не менее 64 байт (обычно гораздо больше). Также будет вестись структура (дерево), где все аллокации, что бы находить дырки по размеру эффективно. Отсюда врубаемся почему malloc на самом то деле не такая уж и быстрая вещь, по сравнению со сборщиком мусора smile

Теперь начнём работать с памятью как со стеком. Стек это общий ресурс, каждый тред может иметь сколько угодно стеков на котором можно создавать/удалять обьекты. Выделяеться память под обьект просто повышая указатель, освобождаеться просто пометкой (не освобождаеться физически). Время от времени тред приостанвливаеться (остальные могут продолжать работать если не ссылаються на стек этого треда), сборщик мусора уплотняет стек. В таком случае высчитывание адреса по смещению от SP' не возможно, только по указателям, что не страшно. Кеширование как и у стека, если создаём и тут же удаляем массу мелких обьектов (обычный ООП подход), то все они  в кеше, соответственно работа быстра. Организация памяти в стек и сборка мусора есть хорошо проверенная техника, используеться в Java.

Вопрос и смысл всего этого флуда:
Получаеться что использование "железного" SP и просто регистра для организации собственного стека в памяти разницы не имеет, т.к. и в том и вдругом случае прога сама изменет регистр-указатель, push'ить целый обьект процы не умеют?
Как организован стек на отличных от x86 процах? (по моему иногда даже железного SP нет, бери любой из массы  регистров).
Имея массу стеков можно проще организовывать треды. Вобще по моему можно все локальные данные гонять в одном стеке, а железный пользовать для вызова процедур и передачи аргументов. Тогда после вызова фрейм фрейм собственного стека можно либо освободить целиком, либо приатачить к куче если есть экспортируемые обьекты.
Чего вообще в голову приходит глядя на текст выше? smile 
И главное: что читать по теме? ссылки, имена, ключевые слова критикующие подход выше очень приветствуються. Восхваление можно найти в дизайнах сборщиков мусора. 


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
regis
Дата 14.7.2006, 13:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 232
Регистрация: 12.12.2005
Где: Москва, Россия

Репутация: нет
Всего: 7



Цитата
Все знают что аллокации переменных на стеке быстрей чем в куче (heap memory), НО! откуда это пошло и так ли это сейчас? smile


Полагаю, что так.

Цитата

Раньше push/pop'или простые значения, сейчас порой сложные обьекты. При создании обьекта на стеке просто поднимают выше значение регистра-указателя-на-верхушку-стека (SP), далее идёт инициализация "полей". При этом вся работа со стеком это увеличение/уменьшения SP, сама инициализация происходит обычными инструкциями по работе с памятью (не мнемоники имею в виду, физически те же инструкции) относительно SP. Плюсы подхода:

    * можно выделить точно требуемое количество байтов (слов) на стеке
    * о скорости поговорим чуть позже smile


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

Цитата
Теперь память. И стек и куча находяться в памяти, перед использованием помещаються в кешь. Если по памяти гулять рандомно, то от кеша пользы мало, проц работает со скоростью FSB. Стек же принуждает находиться в одной странице кеша. Кстати именно из-за кеша опровергнем ранее верную теорию: циклы и вызов малых функций медленней чем просто полотно комманд, поэтому циклы разворачивали, а функции включали (inline) в код. На современных процах чем меньше требуеться подкачивать инфу с общей памяти в кешь, чем больше кешь реюзаеться (циклы, малые функции), тем быстрее прога! smile


Не совсем понял, почему эта идея опровергнута. Если некоторое количество инструкций, которые надо выполнить в цикле, вынести в одину или несколько подпрограмм, загрузка на внутренние кеши только возрастет (не говоря уж о том, что накладные расходы на вызов/возврат из подпрограмм добавятся).

Цитата
Вторая проблема памяти это её выделение операционной системой. Физически нельзя выделить один int (да, иногда пишут new int smile ) в памяти, по любому будет выделен целый блок размером не менее 64 байт (обычно гораздо больше). Также будет вестись структура (дерево), где все аллокации, что бы находить дырки по размеру эффективно. Отсюда врубаемся почему malloc на самом то деле не такая уж и быстрая вещь, по сравнению со сборщиком мусора smile 


Строго говоря, память в C/C++ сначала выделяют стандартные библиотеки, и только потом (если подходящего свобободного куска не нашлось) -- ОС. И откуда эта цифра -- 64 байт? Думаю, для стандартных malloc/free дискретность куда меньше -- 16 байт, или что-то в этом роде.

Цитата
Теперь начнём работать с памятью как со стеком. Стек это общий ресурс, каждый тред может иметь сколько угодно стеков на котором можно создавать/удалять обьекты. Выделяеться память под обьект просто повышая указатель, освобождаеться просто пометкой (не освобождаеться физически). Время от времени тред приостанвливаеться (остальные могут продолжать работать если не ссылаються на стек этого треда), сборщик мусора уплотняет стек. В таком случае высчитывание адреса по смещению от SP' не возможно, только по указателям, что не страшно. Кеширование как и у стека, если создаём и тут же удаляем массу мелких обьектов (обычный ООП подход), то все они  в кеше, соответственно работа быстра. Организация памяти в стек и сборка мусора есть хорошо проверенная техника, используеться в Java.


Хммм... Насколько я понимаю в многопоточности, у каждого треда есть собственный стек. Тем не менее, он не перестает быть стеком, т.е. дисциплина LIFO, расширяется-уплотняется как обычно и т.п. И естественно, доступ к данным через SP, а как иначе?

Цитата
Вопрос и смысл всего этого флуда:
Получаеться что использование "железного" SP и просто регистра для организации собственного стека в памяти разницы не имеет, т.к. и в том и вдругом случае прога сама изменет регистр-указатель, push'ить целый обьект процы не умеют?
Как организован стек на отличных от x86 процах? (по моему иногда даже железного SP нет, бери любой из массы  регистров).


В разных процессорах -- по разному. В достопамятном DEC PDP-11 регистра стэка как такового не было -- использовался регистр общего назначения R6. И ничего, программистам это не мешало. ;)

Цитата
Имея массу стеков можно проще организовывать треды.


Опять не совсем понял мысль. (Как в принципе можно организовать многопоточность, НЕ имея "массы стеков"?)

Цитата
Чего вообще в голову приходит глядя на текст выше? smile 


Упорно лезет в голову мысль, что я не уловил суть идеи.  smile 
 
--------------------
В. В чем разница между hardware и software?О. В отличие от второго, по первому можно двинуть кулаком или пнуть ногой.
PM MAIL WWW   Вверх
Sardar
Дата 14.7.2006, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 1
Всего: 317



Цитата(regis @  14.7.2006,  12:28 Найти цитируемый пост)
Вроде-бы, во всех современных ОС стек будет расти со страничной гранулярностью. 

Как "железный", так и "собственоручно сделанный".

Цитата(regis @  14.7.2006,  12:28 Найти цитируемый пост)
Если некоторое количество инструкций, которые надо выполнить в цикле, вынести в одину или несколько подпрограмм, загрузка на внутренние кеши только возрастет (не говоря уж о том, что накладные расходы на вызов/возврат из подпрограмм добавятся).

Если они упакованы рядом, то нагрузка на кеш как раз снижаеться. Современный кеш > 512кб поделённый на блоки (64 байта по моему чаще всего). Туда запросто влезет цикл и пара мелких функций, если исполнение ограничиваеться только этими инструкциями (например итеративно вычисляем чего нибудь до нужной точности), то фишка работает очень быстро. Если же прога одним полотном, то код приходиться догружать постоянно. Идея пошла отсюда, смысл в том что байткод который обычно меньше по размеру чем транслированный код может быть быстрее, если интерпретатор помещаеться в кеш.

Цитата(regis @  14.7.2006,  12:28 Найти цитируемый пост)
И откуда эта цифра -- 64 байт? Думаю, для стандартных malloc/free дискретность куда меньше -- 16 байт, или что-то в этом роде.

Чем меньше блок, тем больше нод в дереве (чём угодно где блоки регистрируем). Заголовок блока зависит от реализации, я писал менеджер памяти для одного девайса (4Мб RAM всего), на заголовок уходило 8 байт: 2 указателя (24битная адресная шина) + длина блока в 4 байтных еденицах. На современном компе в минимум 2ГБ доступной оперативы как то не серьёзно выделять (заголовк + блок) менее 64 байт... ИМХО

Цитата(regis @  14.7.2006,  12:28 Найти цитируемый пост)
Строго говоря, память в C/C++ сначала выделяют стандартные библиотеки, и только потом (если подходящего свобободного куска не нашлось) -- ОС

Строго говоря ось не умеет выделять блоки памяти по моему, можно только отодвинуть границу конца виртуальной памяти (добавить "меппингов"). Прога либами распределяет память сама, но это уже детали, вопрос в другом smile

Цитата(regis @  14.7.2006,  12:28 Найти цитируемый пост)
Хммм... Насколько я понимаю в многопоточности, у каждого треда есть собственный стек.

Имел в виду не железный стек (обновление SP при переключении контекста), а привязка нескольких стеков к треду. Железный стек нужен процу для вызовов функций. Фиксированный лист аргументов удобно тоже положить на "железный стек". Опциональные аргументы и локальные перменные + вообще вычисления можно вести на отдельных стеках, при этом компилер по коду выявляет когда обьект возвращаеться в мир, а когда создаётсья и уничтожаеться в функции. В первомслучае добавляем обьект в отдельный стек, которым приатачим блоком к "куче"(heap). Второе просто растёт и не засоряет железный стек, хотя и потребуеться подгрузить инфу в кешь. Идея в том что нет надобности записывать такую инфу в память, по этому при возврате из функции если проц видит свой кешь, то его можно просто обнулить. Нет обращения к памяти, нет издежки. Ловля блох, но всё же smile

Цитата(regis @  14.7.2006,  12:28 Найти цитируемый пост)
Опять не совсем понял мысль. (Как в принципе можно организовать многопоточность, НЕ имея "массы стеков"?)

Как сказал выше "масса стеков" у одного треда. Сам стек может помещаться в некий общий большой сегмент памяти для треда, сегменты с фиксированным размером. Это упрощает сборщик мусора. Другими словами:
  • Ось выделяет память под софтину, одна болсьшая виртуальная простыня с границей.
  • Софтина запускает менеджер-памяти-сборщик-мусора что делит память на сегменты фиксированного размера
  • каждый сегмент это стек, треды расхватывают и освобожают сегменты, но внутри сегмента работа как со стеком
  • время от времени менеджер-памяти-сборщик-мусора останавливает один из тредов + ставит синхорнизационный флаг для всех кто обращаеться в чужой сегмент, затем очищает сегмент перенося живые обьекты в другой сегмент. Только сегменты используемые несколькими тредами должны вот так очищаться. Локальные переменные лежат в своём стеке(а значит сегменте) и освобожаються целым сегментом сразу.

Вопрос родился  когда я в очередной раз прочёл (в дизайне и критике C--) что создавать обьекты на стеке это быстро. Все кто сравнивает C++ с Java тоже приводят этот аргумент. Отсюда родилась идея с сегментами и стеками. Т.к. идея тривиальна, естественно она уже давно известна и отработанна, НО! к удивленю моему пишут только положительные стороны (вкупе со сборщиком мусора).

Меня интересует критика такой организации памяти. Также интересны альтернативы ещё быстрей. Ну и наконец собственные мысли где могут возникнуть проблемы или наоборот успешная железная поддержка, например эффективная синхорнизация сегментов между тредами (атомарные swap/test-set знаем, альтернативы?). Интересны ключевые слова по которым можно найти инфу, без воды, без рекламы, знающими людьми. 


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Cr@$h
Дата 14.7.2006, 20:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Исследователь
***


Профиль
Группа: Участник Клуба
Сообщений: 1693
Регистрация: 3.4.2005
Где: Санкт-Петербург, Россия

Репутация: 1
Всего: 41



Цитата(Sardar @  14.7.2006,  15:27 Найти цитируемый пост)
байткод который обычно меньше по размеру чем транслированный код может быть быстрее

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

В дизайнах сборщиков мусора могут восхвалять что угодно и будут правы. Сейчас это дело довольно хорошо отработано. Хотя истинных алгоритмов тебе никто не скажет. Как говорят разработчики Java -- это "style of art". Уверен применяемые концепции, идеи и методы исключительно хороши для сборщиков мусора, но это вовсем не значит, что выполнение самого управляемого кода будут вестись быстрее, чем неуправляемого.

P.S. Надеюсь тредами ты называешь потоки. smile  
PM MAIL ICQ   Вверх
Sardar
Дата 15.7.2006, 00:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 1
Всего: 317



Цитата(Cr@$h @  14.7.2006,  19:43 Найти цитируемый пост)
Если байт код сам по себе меньше, это совсем не значит, что при его выполнении процу понадобится выполнять меньшее число операций.

Нет, я имел в виду что больше байткода влезает в один "забор в кеш", т.е. меньше обращений к памяти. Сам байткод высокоуровневый, вообще его лучше в threaded код обращать (не путать с потоками, как в Fort'e в смысле). Тогда он компактный и шустрый .

Цитата(Cr@$h @  14.7.2006,  19:43 Найти цитируемый пост)
Надеюсь тредами ты называешь потоки.

Да потоки, только ИМХО не корректное это слово, ассоциируеться с каналами (channel, IO и т.д.)

Цитата(Cr@$h @  14.7.2006,  19:43 Найти цитируемый пост)
Хотя истинных алгоритмов тебе никто не скажет. Как говорят разработчики Java -- это "style of art"

Почему же, инфы на эту тему масса. Просто часто бывают не обоснованные заявления, одно из них привёл здесь "стек всегда быстрей чем работа с кучей". Соответственно современные менеджеры памяти, та же ява, работают памятью как со стеком (выделение под обьекты). Где то есть сомнения что не универсален этот подход и будут сложности под разными платформами (процами). Потому спросил критику.

Значит пока такая организация памяти наиболее быстра, в любом случае быстрей чем традиционный malloc. А что будет если процов станет > 20, малые процы типа Cell? (в PS3 пользуються, их время ещё придёт). Скорость процов будет ниже, за то их будет больше, следовательно выигрывать на кеше станет сложней. Также если сегменты будут расшариваьтся тредами (метод обьекта вызываемый из двух тредов например), то кешь вообще постоянно обнуляться будет. В этом направлении кто нибудь задумывался?  


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Cr@$h
Дата 15.7.2006, 00:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Исследователь
***


Профиль
Группа: Участник Клуба
Сообщений: 1693
Регистрация: 3.4.2005
Где: Санкт-Петербург, Россия

Репутация: 1
Всего: 41



Цитата(Sardar @  15.7.2006,  01:31 Найти цитируемый пост)
Да потоки, только ИМХО не корректное это слово, ассоциируеться с каналами (channel, IO и т.д.)

Может быть. У меня с каналом больше pipe ассоциируется smile 
 smile В Lingvo Computer также даёт тред, но тому словарю я не привык доверять. LingvoComputer даёт нить, а вот это уже более часто встречаешь в профессиональных кругах. Дело в том, что я сам люблю перевод, а не заимствование. Взять ту же юзабилити -- это практичность, скорее (удобоиспользуемости нет).
Цитата(Sardar @  15.7.2006,  01:31 Найти цитируемый пост)
Просто часто бывают не обоснованные заявления, одно из них привёл здесь "стек всегда быстрей чем работа с кучей". 

В конечном итоге такие вещи проверяются на практике. 
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила раздела "Философия программирования":
Се ля ви

Форум "Философия программирования" предназначен для обсуждения вопросов, так или иначе связанных с философскими аспектами разработки ПО:

• вопросы перспективного развития методов написания ПО;

• изменяющиеся языки и методологии программирования;


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Се ля ви.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Философия программирования | Следующая тема »


 




[ Время генерации скрипта: 0.2802 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.