Что каждый программист должен знать о памяти pdf

Анатомия программы в памяти

Управление памятью – одна из главных задач ОС. Она критична как для программирования, так и для системного администрирования. Я постараюсь объяснить, как ОС работает с памятью. Концепции будут общего характера, а примеры я возьму из Linux и Windows на 32-bit x86. Сначала я опишу, как программы располагаются в памяти.

Каждый процесс в многозадачной ОС работает в своей «песочнице» в памяти. Это виртуальное адресное пространство, которое в 32-битном режиме представляет собою 4Гб блок адресов. Эти виртуальные адреса ставятся в соответствие (mapping) физической памяти таблицами страниц, которые поддерживает ядро ОС. У каждого процесса есть свой набор таблиц. Но если мы начинаем использовать виртуальную адресацию, приходится использовать её для всех программ, работающих на компьютере – включая и само ядро. Поэтому часть пространства виртуальных адресов необходимо резервировать под ядро.

Это не значит, что ядро использует так много физической памяти – просто у него в распоряжении находится часть адресного пространства, которое можно поставить в соответствие необходимому количеству физической памяти. Пространство памяти для ядра отмечено в таблицах страниц как эксклюзивно используемое привилегированным кодом, поэтому если какая-то программа пытается получить в него доступ, случается page fault. В Linux пространство памяти для ядра присутствует постоянно, и ставит в соответствие одну и ту же часть физической памяти у всех процессов. Код ядра и данные всегда имеют адреса, и готовы обрабатывать прерывания и системные вызовы в любой момент. Для пользовательских программ, напротив, соответствие виртуальных адресов реальной памяти меняется, когда происходит переключение процессов:

Голубым отмечены виртуальные адреса, соответствующие физической памяти. Белым – пространство, которому не назначены адреса. В нашем примере Firefox использует гораздо больше места в виртуальной памяти из-за своей легендарной прожорливости. Полоски в адресном пространстве соответствуют сегментам памяти таким, как куча, стек и проч. Эти сегменты – всего лишь интервалы адресов памяти, и не имеют ничего общего с сегментами от Intel. Вот стандартная схема сегментов у процесса под Linux:

Когда программирование было белым и пушистым, начальные виртуальные адреса сегментов были одинаковыми для всех процессов. Это позволяло легко удалённо эксплуатировать уязвимости в безопасности. Зловредной программе часто необходимо обращаться к памяти по абсолютным адресам – адресу стека, адресу библиотечной функции, и т.п. Удаленные атаки приходилось делать вслепую, рассчитывая на то, что все адресные пространства остаются на постоянных адресах. В связи с этим получила популярность система выбора случайных адресов. Linux делает случайными стек, сегмент отображения в память и кучу, добавляя смещения к их начальным адресам. К сожалению, в 32-битном адресном пространстве особо не развернёшься, и для назначения случайных адресов остаётся мало места, что делает эту систему не слишком эффективной.

Самый верхний сегмент в адресном пространстве процесса – это стек, в большинстве языков хранящий локальные переменные и аргументы функций. Вызов метода или функции добавляет новый кадр стека (stack frame) к существующему стеку. После возврата из функции кадр уничтожается. Эта простая схема приводит к тому, что для отслеживания содержимого стека не требуется никакой сложной структуры – достаточно всего лишь указателя на начало стека. Добавление и удаление данных становится простым и однозначным процессом. Постоянное повторное использование районов памяти для стека приводит к кэшированию этих частей в CPU, что добавляет скорости. Каждый поток выполнения (thread) в процессе получает свой собственный стек.

Можно прийти к такой ситуации, в которой память, отведённая под стек, заканчивается. Это приводит к ошибке page fault, которая в Linux обрабатывается функцией expand_stack(), которая, в свою очередь, вызывает acct_stack_growth(), чтобы проверить, можно ли ещё нарастить стек. Если его размер не превышает RLIMIT_STACK (обычно это 8 Мб), то стек увеличивается и программа продолжает исполнение, как ни в чём не бывало. Но если максимальный размер стека достигнут, мы получаем переполнение стека (stack overflow) и программе приходит ошибка Segmentation Fault (ошибка сегментации). При этом стек умеет только увеличиваться – подобно государственному бюджету, он не уменьшается обратно.

Динамический рост стека – единственная ситуация, в которой может осуществляться доступ к свободной памяти, которая показана белым на схеме. Все другие попытки доступа к этой памяти вызывают ошибку page fault, приводящую к Segmentation Fault. А некоторые занятые области памяти служат только для чтения, поэтому попытки записи в эти области также приводят к Segmentation Fault.

После стека идёт сегмент отображения в память. Тут ядро размещает содержимое файлов напрямую в памяти. Любое приложение может запросить сделать это через системный вызов mmap() в Linux или CreateFileMapping() / MapViewOfFile() в Windows. Это удобный и быстрый способ организации операций ввода и вывода в файлы, поэтому он используется для подгрузки динамических библиотек. Также возможно создать анонимное место в памяти, не связанное с файлами, которое будет использоваться для данных программы. Если вы сделаете в Linux запрос на большой объём памяти через malloc(), библиотека C создаст такую анонимное отображение вместо использования памяти из кучи. Под «большим» подразумевается объём больший, чем MMAP_THRESHOLD (128 kB по умолчанию, он настраивается через mallopt().)

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

Если в куче оказывается недостаточно места для выполнения запроса, эту проблему может обработать сама программа без вмешательства ядра. В ином случае куча увеличивается системным вызовом brk(). Управление кучей – дело сложное, оно требует хитроумных алгоритмов, которые стремятся работать быстро и эффективно, чтобы угодить хаотичному методу размещению данных, которым пользуется программа. Время на обработку запроса к куче может варьироваться в широких пределах. В системах реального времени есть специальные инструменты для работы с ней. Кучи тоже бывают фрагментированными:

Пример данных на диаграмме будет немного сложнее, поскольку он использует указатель. В этом случае содержимое указателя, 4-байтный адрес памяти, живёт в сегменте данных. А строка, на которую он показывает, живёт в сегменте текста, который предназначен только для чтения. Там хранится весь код и разные другие детали, включая строковые литералы. Также он хранит ваш бинарник в памяти. Попытки записи в этот сегмент оканчиваются ошибкой Segmentation Fault. Это предотвращает ошибки, связанные с указателями (хотя не так эффективно, как если бы вы вообще не использовали язык С). На диаграмме показаны эти сегменты и примеры переменных:

Изучить области памяти Linux-процесса можно, прочитав файл /proc/pid_of_process/maps. Учтите, что один сегмент может содержать много областей. К примеру, у каждого файла, сдублированного в память, есть своя область в сегменте mmap, а у динамических библиотек – дополнительные области, напоминающие BSS и данные. Кстати, иногда, когда люди говорят «сегмент данных», они имеют в виду данные + bss + кучу.

Бинарные образы можно изучать при помощи команд nm и objdump – вы увидите символы, их адреса, сегменты, и т.п. Схема виртуальных адресов, описанная в этой статье – это т.н. «гибкая» схема, которая по умолчанию используется уже несколько лет. Она подразумевает, что переменной RLIMIT_STACK присвоено какое-то значение. В противном случае Linux использует «классическую» схему:

Источник

Что каждый программист должен знать о памяти

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

1 Введение

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

Эта ситуация изменилась с тех пор как основная структура компьютеров стабилизировалась, и разработчики аппаратного обеспечения сконцентрировались на оптимизации отдельных подсистем. Неожиданно производительность некоторых подсистем отстала от других, и образовались так называемые «бутылочные горлышки». Это, прежде всего, относится к подсистемам хранения данных и памяти, которые из соображений стоимости улучшались медленнее по сравнению с другими компонентами.

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

В отличие от подсистемы хранения данных, устранение проблемы «бутылочного горлышка» для случая основной памяти оказалось более трудным делом, и почти все решения тут требуют изменений в аппаратном обеспечении. На сегодня эти изменения происходят в основном в следующих сферах:

Этот документ посвящен в основном кэшам ЦПУ и некоторым эффектам проектирования контроллеров памяти. В процессе исследования этих тем, мы рассмотрим прямой доступ к памяти (DMA) с целью его роли в общей картине. Однако начнем мы с обзора современного аппаратного обеспечения компьютеров. Это потребуется для понимания проблем и ограничений эффективного использования подсистемы памяти. Мы также расскажем о различных типах RAM и о том, почему различия все ещё существуют.

Этот документ ни в коем случае не претендует на полноту. Он ограничивается массовыми компьютерами и некоторым подмножеством их аппаратного обеспечения. Некоторые темы будут обсуждаться лишь настолько подробно, насколько это необходимо для целей этой статьи. Читателям рекомендуется найти более детальную документацию по таким темам.

Когда речь идет о деталях, специфичных для некоторой ОС, и используемых в ОС решениях, речь идет исключительно о Linux. О других ОС не будет дано никакой информации. У автора отсутствует интерес к обсуждению результатов, получающихся для других ОС. Если читатель считает, что он должен использовать другую ОС, он должен потребовать от её производителей написать подобный документ.

Последний комментарий перед началом. Текст содержит некоторое количество терминов «обычно» и других в кавычках. Технология, описываемая здесь, существует реальном мире во множестве вариаций, и эта статья описывает только наиболее распространенные версии. Нечасто бывает возможность делать утверждения, применимые абсолютно ко всем вариантам технологии, отсюда и кавычки.

1.1 Структура документа

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

Третья глава в деталях описывает поведение кэша ЦПУ. Чтобы текст был не таким сухим, используются рисунки. Эта глава существенно необходима для понимания остальной части документа. Глава 4 кратко описывает строение виртуальной памяти. Эта глава также необходима для остального.

Глава 5 описывает в деталях системы, построенные по технологии Non Uniform Memory Access (NUMA).

Глава 7 представляет инструменты, которые могут помочь программисту делать свою работу эффективнее. Даже при полном понимании технологии в сложных программных проектах бывает неочевидно, где кроются проблемы. Некоторые инструменты необходимы.

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

1.2 Сообщения об ошибках

Автор намерен обновлять этот документ в случае обнаружения ошибок и при прогрессе технологий. Читатели, желающие сообщить об ошибках, могут сделать это при помощи электронной почты.

1.3 Благодарности

Хотел бы поблагодарить Джонрэя Фуллера и особенно Джонотана Корбета за участие в непосильной работе по приведению английского языка автора к более или менее общепринятой форме. Маркус Армбрустер предоставил много ценного материала о проблемах и упущениях текста.

1.4 Об этом документе

Заголовок этой статьи отдает дань классической статье Давида Голдберга «Что каждый программист должен знать об арифметике чисел с плавающей точкой». Эта статья все ещё не так широко известна, хотя каждый, кто садится за клавиатуру для серьезного программирования, должен её знать.

Источник

Что Каждый Программист Должен Знать О Памяти?

3 ответов:

насколько я помню, содержание Drepper описывает фундаментальные понятия о памяти: как работает кэш процессора, что такое физическая и виртуальная память и как ядро Linux имеет дело с этим зоопарком. Возможно, в некоторых примерах есть устаревшие ссылки на API, но это не имеет значения; это не повлияет на актуальность фундаментальных понятий.

Итак, любая книга или статья, описывающая что-то фундаментальное, не может быть названа устаревшей. «Что каждый программист должен знать о памяти» определенно стоит прочитать, но, Ну, я не думаю, что это для «каждого программиста». Это больше подходит для системных / встроенных / ядра парней.

от моего быстрого взгляда-через это выглядит довольно точно. Единственное, что нужно заметить, это часть о разнице между» интегрированными «и» внешними » контроллерами памяти. С момента выпуска линейки i7 процессоры Intel все интегрированы, и AMD использует интегрированные контроллеры памяти с момента первого выпуска чипов AMD64.

Так как эта статья была написана, не все изменилось, скорость стала выше, контроллеры памяти получили гораздо больше интеллектуальный (i7 будет задерживать запись в ОЗУ, пока не почувствует, что совершает изменения), но не так много изменилось. По крайней мере, не в любом случае, что разработчик программного обеспечения будет волновать.

это все же очень обидно. (мной, и я думаю, другими экспертами по настройке производительности). Было бы здорово, если бы Ульрих (или кто-то еще) написал обновление 2017 года, но это было бы много работы (например, повторный запуск тестов). См. также другие ссылки на оптимизацию производительности x86 и SSE/asm (и C / C++) в x86 метки. (Статья Ульриха не относится к x86, но большинство (все) его тестов находятся на оборудовании x86.)

аппаратные детали низкого уровня о том, как работают DRAM и кэши, все еще применяются. Память DDR4 использует те же команды как описано для DDR1 / DDR2 (чтение / запись пакета). Улучшения DDR3 / 4 не являются фундаментальными изменениями. AFAIK, все arch-независимые вещи по-прежнему применяются в целом, например, к AArch64 / ARM32.

таким образом предложение Ульриха в 6.5.8 Использование Всей Полосы Пропускания (при использовании удаленной памяти на других узлах NUMA, а также на вашем собственном) является контрпродуктивным на современном оборудовании, где контроллеры памяти имеют большую пропускную способность, чем может использовать одно ядро. Ну, возможно, вы можете представить себе ситуацию, когда есть некоторое преимущество для запуска нескольких потоков памяти на одном узле NUMA для межпотоковой связи с низкой задержкой, но при этом они используют удаленную память для высокая пропускная способность, не чувствительная к задержке. Но это довольно неясно; обычно вместо намеренного использования удаленной памяти, когда вы могли бы использовать локальную, просто разделите потоки между узлами NUMA и попросите их использовать локальную память.

(обычно) не используйте программное обеспечение prefetch

одна важная вещь, которая изменилась, это то, что аппаратная предварительная выборка много лучше, чем на P4 и смогите узнать strided картины доступа до справедливо большого шаг и несколько потоков одновременно (например, один вперед / назад на страницу 4k). руководство по оптимизации Intel описывает некоторые детали HW prefetchers в различных уровнях кэша для их микроархитектуры семейства Sandybridge. Ivybridge и позже имеют аппаратную предварительную выборку следующей страницы, вместо того, чтобы ждать промаха кэша на новой странице, чтобы вызвать быстрый запуск. (Я предполагаю, что AMD имеет некоторые подобные вещи в своем Руководстве по оптимизации.) Помните, что руководство Intel также полно старых советы, некоторые из которых хороши только для P4. Конкретные разделы Sandybridge, конечно, точны для SnB, но, например,un-ламинирование микро-сплавленных uops изменилось в HSW, и руководство не упоминает об этом.

обычный совет в эти дни, чтобы удалить все SW prefetch из старого кода, и только подумайте о том, чтобы вернуть его, если профилирование показывает промахи кэша (и вы не насыщаете пропускную способность памяти). Предварительная выборка с обеих сторон далее шаг двоичного поиска все еще может помочь. например, как только вы решите, какой элемент смотреть дальше, предварительно выберите элементы 1/4 и 3/4, чтобы они могли загружаться параллельно с загрузкой/проверкой середины.

предварительная выборка программного обеспечения всегда была «хрупкой»: правильные магические номера настройки для ускорения зависят от деталей оборудования и, возможно, системы нагрузка. Слишком рано, и он выселяется до нагрузки спроса. Слишком поздно и это не поможет. в этой статье показывает код + графики для интересного эксперимента по использованию SW prefetch на Haswell для предварительной выборки непоследовательной части проблемы. Смотрите также Как правильно использовать инструкции prefetch?. NT prefetch интересен, но еще более хрупок (потому что раннее выселение из L1 означает, что вам нужно пройти весь путь до L3 или DRAM, а не только L2). Если вам нужно до последней капли производительности,и вы можете настроить для конкретной машины, SW prefetch стоит посмотреть на последовательный доступ, но если мая все еще будет замедление, если у вас достаточно работы ALU, чтобы сделать, приближаясь к узкому месту в памяти.

размер строки кэша по-прежнему составляет 64 байта. (Пропускная способность чтения/записи L1D составляет очень высокие, и современные процессоры могут делать 2 вектора нагрузок в часы + 1 вектора магазине, если все это попадает в L1D. См как кэш может быть так быстро?.) С AVX512, размер линии = ширина вектора, так что вы можете загрузить/сохранить всю строку кэша в одной инструкции. (И, таким образом, каждая несоосная загрузка / хранилище пересекает границу кэш-линии, а не каждую другую для 256b AVX1 / AVX2, которая часто не замедляет цикл по массиву, который не был в L1D.)

невыровненные инструкции загрузки имеют нулевой штраф, если адрес выровнен во время выполнения, но компиляторы (особенно gcc) улучшают код, когда автовекторизация, если они знают о каких-либо гарантиях выравнивания. На самом деле невыровненные ops, как правило, быстро, но разбиение страниц все еще больно (гораздо меньше на Skylake, хотя; только

11 дополнительных циклов задержки против 100, но все же штраф за пропускную способность).

как и предсказывал Ульрих, каждый Multi-гнездо система NUMA в наши дни: интегрированные контроллеры памяти являются стандартными, т. е. нет внешнего Северного моста. Но SMP больше не означает мульти-сокет, потому что многоядерные процессоры широко распространенный. (Процессоры Intel от Nehalem до Skylake использовали большой включительно кэш L3 в качестве опоры для обеспечения согласованности между ядрами.) Процессоры AMD разные, но я не так ясно понимаю детали.

Skylake-X (AVX512) больше не имеет инклюзивного L3, но я думаю, что все еще есть каталог тегов, который позволяет ему проверять, что кэшируется в любом месте на чипе (и если да, то где) без фактического вещания snoops на все ядра. SKX использует сетку, а не кольцо автобус, как правило, с еще худшей задержкой, чем предыдущие многоядерные Xeons, к сожалению.

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

6.4.2 Atomic ops: бенчмарк показывает в CAS-повторить петли в 4 раза хуже, чем аппаратно-решается lock add вероятно, все еще отражает a максимум утверждение случае. Но в реальных многопоточных программах синхронизация сведена к минимуму (потому что это дорого), поэтому конкуренция низка, и цикл CAS-retry обычно успешно выполняется без необходимости повторять попытку.

C++11 std::atomic fetch_add будет составлять с lock add (или lock xadd если используется возвращаемое значение), но алгоритм, использующий CAS, чтобы сделать что-то, что не может быть сделано с помощью lock инструкция ed обычно не является катастрофой. Используйте C++11 std::atomic или C11 stdatomic вместо GCC legacy __sync встроенные модули или новее __atomic встроенные модули если вы не хотите смешивать атомарный и неатомный доступ к одному и тому же местоположению.

8.1 DCAS ( cmpxchg16b ): вы можете уговорить gcc излучать его, но если вы хотите эффективные нагрузки только на одну половину объекта, вам нужно уродливо union хаки: как я могу реализовать счетчик ABA с c++11 КАС?

8.2.4 транзакций: после нескольких ложных запусков (выпущенных затем отключенных обновлением микрокода из-за редко срабатывающей ошибки) Intel имеет рабочую транзакционную память в последней модели Broadwell и всех процессорах Skylake. Дизайн по-прежнему то, что Дэвид Кантер описал для Хасвелла. Есть способ lock-ellision использовать его для ускорения кода, который использует (и может вернуться) обычный замок (особенно с одним замком для всех элементы контейнера, поэтому несколько потоков в одном и том же критическом разделе часто не сталкиваются), или написать код, который знает о транзакциях напрямую.

2mib-выровненное анонимное распределение будет использовать огромные страницы по умолчанию. Некоторые рабочие нагрузки (например, которые продолжают использовать большие выделения в течение некоторого времени после их создания) могут извлечь выгоду из
echo always >/sys/kernel/mm/transparent_hugepage/defrag чтобы получить ядра для дефрагментации физической памяти, когда это необходимо, вместо того, чтобы падать обратно на 4К страниц. (См.ядре документы). Кроме того, используйте madvise(MADV_HUGEPAGE) после делать большие распределения (предпочтительно все еще с 2миб юстировка.)

Источник

Что каждый программист должен знать о памяти

Один из разработчиков ядра, Ulrich Drepper, начал публикацию своего труда, «Что каждый программист должен знать о памяти» («What every programmer should know about memory»), описывающий то, как взаимодействуют программное обеспечение и системная память. Несмотря на то, что эффективность работы памяти зачастую определяет эффективность работы всей программы, материалов на тему того, как избежать узких мест в ее производительности не так много. Данная работа призвана устранить этот недостаток.

Публикация разбита на семь частей, каждая из которых будет появляться с периодичностью в одну-две недели после предыдущей. Публикация производится сайтом http://lwn.net, выкладываемые части некоторое время будут доступны только подписчикам. После того как будут выложены все части, текст будет выложен в публичный доступ.

Re: Что каждый программист должен знать о памяти

После выхода всех частей, хотелось бы видеть научно-технический перевод на русский язык.

Re: Что каждый программист должен знать о памяти

Он должен знать то, что памяти никогда не бывает много.

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

>Желающие прочитать первую часть сейчас, и притом бесплатно

Премного благодарен. А если я немного задержусь, то сколько это будет стоить?

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

Само по себе значение не вредно. Лучше сформулировать так: чем меньше мы _обязаны_ знать о работе с памятью, тем лучше. Или так: чем реже требуется знание о низкоуровневой работе с памятью, тем лучше.

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

>Само по себе значение не вредно. Лучше сформулировать так: чем меньше >мы _обязаны_ знать о работе с памятью, тем лучше. Или так: чем реже >требуется знание о низкоуровневой работе с памятью, тем лучше.

Или (на мой взгляд) НИЧЕГО не может быть много! Ко ВСЕМ ресурсам мы ОБЯЗАНЫ относится бережно! В том числе и к размеру кода!

Re: Что каждый программист должен знать о памяти

Порой бывает проще купить дополнительно памяти.

Re: Что каждый программист должен знать о памяти

это что за глупости? там же compilation error при ОТСУТСТВИИ break или return

Re: Что каждый программист должен знать о памяти

> По поводу 256Мб каждому программисту. даже Visual Studio 2005 не запустишь. Не говоря уже о 2008.

Вот и правильно было бы. Тр***лись бы не те, кто вынужден использовать это дотнетные поделки восьмиклассников, а те, кто их пытается писать.

Re: Что каждый программист должен знать о памяти

>>По поводу 256Мб каждому программисту. даже Visual Studio 2005 не запустишь. Не говоря уже о 2008.

>Вот и правильно было бы. Тр***лись бы не те, кто вынужден использовать это дотнетные поделки восьмиклассников, а те, кто их пытается писать.

+1 дотнет в большую топку!

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

Зашоренный фонатег он

Re: Что каждый программист должен знать о памяти

> Само по себе значение не вредно. Лучше сформулировать так: чем меньше мы _обязаны_ знать о работе с памятью, тем лучше. Или так: чем реже требуется знание о низкоуровневой работе с памятью, тем лучше.

Вы хоть Джоэла почитайте что ли, чтобы знать, к чему приводит незнание низкоуровневых особенностей аппаратуы и реализации при программировании. Ну или гуглите по словам «алгоритм маляра Шлемиля» и «закон дырявых абстракций».

Re: Что каждый программист должен знать о памяти

> По поводу 256Мб каждому программисту. даже Visual Studio 2005 не запустишь. Не говоря уже о 2008.

> Вот и правильно было бы. Тр***лись бы не те, кто вынужден использовать это дотнетные поделки восьмиклассников, а те, кто их пытается писать.

Не знаю что там с абстрактными дотнетными поделками, а вот к ОО, FF, KDE, Gnome это напрямую относится.

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

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

Re: Что каждый программист должен знать о памяти

> Порой бывает проще купить дополнительно памяти.

Лузир! Открой глаза, у тебя уже слоты все кончились и регистровая память максимального объёма стоит. Шо? «Всё так же тормозит»? Можно ещё раз, я не расслышал. =)

Re: Что каждый программист должен знать о памяти

>это что за глупости? там же compilation error при ОТСУТСТВИИ break или return

Ну-ка, ну-ка, а можно поподробнее? Я правильно понял, что если внутри switch-а у какого-то case не будет стоять break, то будет compilation error? Хренасе! А если мне НАДО, чтобы в случае такого-то case выполнился этот и ещё следующий за ним? Дублировать? Выносить отдельно? Мдя.

Re: Что каждый программист должен знать о памяти

Так, вроде, там можно поставить континуе.

Re: Что каждый программист должен знать о памяти

Что касается шарпов, паскалей, джав и др. языков высокого уровня, то там и вообще нечего замарачиваться. Там только следи, когда сборщик лучше пнуть (если только есть такая возможность).

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

Нет, неправиль. Советую вникать в вопрос сначала или снижать тон =) Просто если тебе там break не нуже логически то ты должен написать goto next; case next : понятно? потому что в большинстве случаев нужно именно break в конце, и если вдург облажался (со всеми бывает, не надо тут выпендриваться) то это поможет найти ошибку ещё при компиляции.

Re: Что каждый программист должен знать о памяти

> gaa (*) (22.09.2007 16:30:54) > Я не против этого. Но в данный момент оно выливается в написание мегакомбайнов типа жабы и дотнета, которые _одинаково_ (плохо) делают все задачи, вместо того, чтобы использовать узкоспециализированные языки, на которые задача ложится легко и эффективно.

Вот только FF хавает память. объясняют фрагментацией.

ИМХО я отдам 2% своего CPU для работы GC чем буду ПОСТОЯННО терять память в подобное программе.

PS системные вещи эффективнее делать на С / С++.

dsohowto Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

>> gaa (*) (22.09.2007 16:30:54) > Я не против этого. Но в данный момент оно выливается в написание мегакомбайнов типа жабы и дотнета, которые _одинаково_ (плохо) делают все задачи, вместо того, чтобы использовать узкоспециализированные языки, на которые задача ложится легко и эффективно.

> Вот только FF хавает память. объясняют фрагментацией.

Огнелис тоже монстр, правда монстр незаменимый. Вот будет в konqueror imglikeopera(а может уже есть?), выкину лиса.

> ИМХО я отдам 2% своего CPU для работы GC чем буду ПОСТОЯННО терять память в подобное программе.

Так просто не откупитесь парой процентов процессорной мощности. Реальный пример нехорошей работы gc: в виртуальной машине установлено ограничение на кол-во памяти в 127мб. Программа создаёт огромную кучу маленьких объектов, заполняя всю память. когда свободная память заканчивается, начинает работать мусорщик, который ищет то, что уже не используется, дефрагментирует память и т.д. В итоге программа повисает на

20 минут, после чего валится с OutOfMemoryException. Это приемлимая ситуация? По-моему, нет.

Смарт поинтер от фрагментации памяти вроде бы не спасает. Или я что-то пропустил в современных технологиях?

> PS системные вещи эффективнее делать на С / С++.

Re: Что каждый программист должен знать о памяти

>Премного благодарен. А если я немного задержусь, то сколько это будет стоить?

Присоединяюсь. На всякий случай сохранил копию страницы :) Кстати, под какой лицензией этот документ?

Re: Что каждый программист должен знать о памяти

> А если мне НАДО, чтобы в случае такого-то case выполнился этот и ещё следующий за ним?

А ты сначала полумай, что тебе сейчас НАДО, а потому кому-то в этом коде разбираться, ага?

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

>> А если мне НАДО, чтобы в случае такого-то case выполнился этот и ещё следующий за ним?

> А ты сначала полумай, что тебе сейчас НАДО, а потому кому-то в этом коде разбираться, ага?

Философский вопрос. Кстати, в C/C++ так принято писать и нормально народ друг друга понимает. Да и тот изврат, что будет придуман взамен множественному case, вряд ли будет уж очень читабельным.

Re: Что каждый программист должен знать о памяти

>Смарт поинтер от фрагментации памяти вроде бы не спасает. Или я что-то пропустил в современных технологиях?

Смарт поинтер удаляет память сразу как только выходит за область видимости, поэтому он предсказуем (поставил скобочки и всё!), в отличии от сборщика мусора. Сборщик запускается КАК ПРАВИЛО только когда памяти УЖЕ нет (это как раз тот момент, когда надо-бы ускориться ;-) )! Некоторые сборщики позволяют им подсказать когда запуститься.

Re: Что каждый программист должен знать о памяти

Все. Вот теперь уж точно кому нибудь да капец.

Re: Что каждый программист должен знать о памяти

Это что за красноглазие?! Ещё как используют! С++ тем и хорош, что можно размахнуться от низкоуровнего C (почти ассемблера) до элегантных эффективных высокоуровневых абстракций.

Re: Что каждый программист должен знать о памяти

>> Смарт поинтер от фрагментации памяти вроде бы не спасает. Или я что-то пропустил в современных технологиях?

> Смарт поинтер удаляет память сразу как только выходит за область видимости, поэтому он предсказуем (поставил скобочки и всё!), в отличии от сборщика мусора.

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

Re: Что каждый программист должен знать о памяти

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

Можно примерчик _системной_ программы на цпп? А то куда ни сунься, везде ц. Может просто не туда суюсь :)

Re: Что каждый программист должен знать о памяти

>Советую вникать в вопрос сначала

Собственно, поэтому вопрос и был задан, что захотелось «вникнуть».

Re: Что каждый программист должен знать о памяти

> Кстати, в C/C++ так принято писать и нормально народ друг друга понимает.

По-моим ощущениям, писать так НЕ принято. А принято писать break.

Re: Что каждый программист должен знать о памяти

>Можно примерчик _системной_ программы на цпп? А то куда ни сунься, везде ц. Может просто не туда суюсь :)

Re: Что каждый программист должен знать о памяти

>А ты сначала полумай, что тебе сейчас НАДО, а потому кому-то в этом коде разбираться, ага?

Просто писать надо аккуратно. Например, у меня натуральный рефлекс сразу ставить закрывающую скобку. И точно такой же рефлекс набирать case BLA_BLA: break; Видимо, у создателей C# такого рефлекса не было, и им часто досаждали собственные ошибки с пропущенным break-ом, раз они пошли на такой шаг. =\

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

Ага ;-). Тогда будет так: Если программа написана человеком.

Re: Что каждый программист должен знать о памяти

>> Можно примерчик _системной_ программы на цпп? А то куда ни сунься, везде ц. Может просто не туда суюсь :)

Re: Что каждый программист должен знать о памяти

>По-моим ощущениям, писать так НЕ принято. А принято писать break.

switch (smt) <
case AAA:
case BCE:
case DFG:
.
case QWERTY:
do_something_1();
break;

case QWE:
case FGH:
case GHJ:
do_something_2();
break;

И как это сделают те, у кого «принято писать break»?
Будут писать do_something_N() в каждом case? Браво!

Re: Что каждый программист должен знать о памяти

>Ага ;-). Тогда будет так: Если программа написана человеком.

Если программа написана.

Re: Что каждый программист должен знать о памяти

Всё то, что вы здесь обсуждаете; про оптимизацию, память, дешевизну компонент, а надо ли оптимизировать программу, очень кратко и содержательно (а также поучительно) написано у Джоэля Спольски: http://www.joelonsoftware.com/items/2007/09/18.html

Re: Что каждый программист должен знать о памяти

Re: Что каждый программист должен знать о памяти

> Просто писать надо аккуратно. Например, у меня натуральный рефлекс >сразу ставить закрывающую скобку. И точно такой же рефлекс набирать >case BLA_BLA: break; Видимо, у создателей C# такого рефлекса не >было, и им часто досаждали собственные ошибки с пропущенным break->ом, раз они пошли на такой шаг. =\

Прочти и устыдись, фанатик:

. В середине декабря 1989 года AT&T произвела обновление программного обеспечения на коммутаторах 4ESS с целью увеличения производительности системы и введения быстрого процесса восстановления после ошибки. Приблизительно в 2:30 по Восточному стандартному времени (EST) 15 января 1990 года на 4ESS коммутаторе в Нью-Йорке возникла небольшая аппаратная проблема, и коммутатор начал процесс восстановления, как было описано выше. После того как Нью-Йоркский коммутатор исправил проблему, он послал сообщение IAM для уведомления соседних коммутаторов, что он готов продолжать работу. Однако обновление программ, проведенное в середине декабря, внесло в действия ошибку. Эта ошибка проявилась, когда коммутатор получил два IAM сообщения с интервалом 1/100 секунды. Некоторые данные в коммутаторе оказались искажены, и он прекратил обслуживание, перейдя к инициализации. Когда соседние узлы выходили из строя, они запускали тот же самый процесс восстановления. Поскольку все коммутаторы были одинаковы, та же последовательность событий каскадом распространялась от одного коммутатора к другому и вывела из строя всю систему.

В течение дня инженеры AT&T смогли стабилизировать сеть, уменьшив нагрузку на нее. К 23:30 EST они смогли очистить все звенья сети, и система практически вернулась к нормальному состоянию.

Во вторник, 16 января 1990 года, инженеры AT&T смогли идентифицировать и выделить ошибку, которая была отслежена до набора ошибочных кодов. Этот код активировался в ходе процедуры восстановления коммутатора. Отрывок кода, который вызвал аварию, представлен ниже41:

3. switch (expression)<

17. >while (expression);

В данном случае виновным оказался оператор break в строке 7. Согласно реализации, если logical_test прошел успешно, программа переходит к строке 6 для выполнения расположенных там операторов. Когда выполнение программы доходит до строки 7, оператор break заставляет программу покинуть блок оператора switch, расположенного между 3 и 15 строками, и исполнять код начиная со строки 16. Однако эта часть исполнения не входила в намерения программиста. Программист желал, чтобы оператор break в седьмой строке прерывал выполнение условного оператора if-then и чтобы после исполнения седьмой строки исполнение продолжилось со строки 11.

Языки для того и сделаны, чтобы от машинных кодов ум за разум не заходил, и не возникало соответствующих ошибок. Создатели C# это прекрасно понимали.

ЗЫ: И ваше C/C++ таки да, г. Заслуженное, но г.

ЗЗЫ: Лисп с Хаскелем и Эрлангом таки всех зарулят. И еще Nemerle. А вы, байтогрызы, без работы останетесь, в управдомы пойдете, только вас не возьмут, за склочность и красноглазие.

Re: Что каждый программист должен знать о памяти

Ну, ты, [skip] развел тут фигню с си-шарповским switch. Возьми и почитай документацию. Может быть, потом будет стыдно.. :)

Источник

Понравилась статья? Поделиться с друзьями:

Не пропустите наши новые статьи:

  • что использует оперативную память windows 10
  • что использует камеру windows 10
  • Что интересного в профессии программиста
  • Что интересного в программировании
  • Что именно делают программисты

  • Операционные системы и программное обеспечение
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии