В таких языках, как C и C++, при использовании указателей на переменные нам требуется еще одна ячейка памяти для хранения этого адреса. Так не является ли это накладными расходами памяти? Как это компенсируется? Используются ли указатели в критических по времени приложениях с малым объемом памяти?
Так не является ли это перерасходом памяти?
Конечно, дополнительный адрес (обычно 4/8 байт в зависимости от процессора).
Как это компенсируется?
Никак. Если вам нужна непрямолинейность, необходимая для указателей, то вам придется за нее заплатить.
Используются ли указатели в критических по времени приложениях с малым объемом памяти?
Я не так много там работал, но я бы предположил, что да. Доступ к указателям - это элементарный аспект программирования на ассемблере. Он занимает тривиальные объемы памяти, а операции с указателями очень быстры - даже в контексте такого рода приложений.
На самом деле, накладные расходы заключаются не в дополнительных 4 или 8 байтах, необходимых для хранения указателя. В большинстве случаев указатели используются для динамического выделения памяти, то есть мы вызываем функцию для выделения блока памяти, и эта функция возвращает нам указатель, который указывает на этот блок памяти. Этот новый блок сам по себе представляет значительные накладные расходы.
Теперь, чтобы использовать указатель, не обязательно выделять память: Вы можете иметь массив int
, объявленный статически или на стеке, и вы можете использовать указатель вместо индекса для обращения к int
, и все это очень красиво, просто и эффективно. Не нужно выделять память, и указатель обычно занимает в памяти ровно столько места, сколько занимал бы целочисленный индекс.
Кроме того, как напомнил нам в своем комментарии Джошуа Тейлор, указатели используются для передачи чего-либо по ссылке. Например, struct foo f; init_foo(&f);
выделит f на стеке, а затем вызовет init_foo()
с указателем на эту struct
. Это очень распространено. (Только будьте осторожны, не передавайте эти указатели "вверх") В C++ вы можете увидеть, что это делается с помощью "ссылки" (foo&
) вместо указателя, но ссылки - это не что иное, как указатели, которые вы не можете изменять, и они занимают тот же объем памяти.
Но основная причина, по которой используются указатели, - это динамическое распределение памяти, и делается это для того, чтобы решить проблемы, которые невозможно решить другим способом. Вот упрощенный пример: Представьте, что вы хотите прочитать все содержимое файла. Где вы собираетесь их хранить? Если вы попытаетесь с буфером фиксированного размера, то вы сможете прочитать только те файлы. которые не длиннее этого буфера. Но, используя выделение памяти распределение памяти, вы можете выделить столько памяти, сколько необходимо для чтения файла, а затем приступить к его чтению.
Кроме того, C++ является объектно-ориентированным языком, и есть определенные аспекты ООП, такие как абстракция, которые достижимы только достижимы только с помощью указателей. Даже такие языки, как Java и C#, делают широкое использование указателей, они просто не позволяют вам напрямую манипулировать указателями, чтобы предотвратить опасные действия с ними. но все же, эти языки начинают иметь смысл только после того, как вы поймете, что за ними скрывается когда вы поймете, что за за кулисами все делается с помощью указателей.
Итак, указатели используются не только в критичных по времени приложениях с малым объемом памяти, они используются всюду.
У меня не совсем такое же отношение к этому, как у Теластина.
Системные глобальные файлы во встроенном процессоре могут быть адресованы определенными, жестко закодированными адресами.
Глобальные файлы в программе адресуются как смещение от специального указателя, который указывает на место в памяти, где хранятся глобальные и статические файлы.
Локальные переменные появляются при вводе функции и адресуются как смещение от другого специального указателя, часто называемого "указателем рамки". Сюда входят аргументы функции. Если вы будете осторожны с толканиями и всплываниями указателя стека, вы можете обойтись без указателя рамки и обращаться к локальным переменным прямо из указателя стека.
Таким образом, вы платите за перенаправление указателей, независимо от того, пробираетесь ли вы через массив или просто захватываете какую-то непримечательную локальную или глобальную переменную. Она просто основана на другом указателе, в зависимости от того, что это за переменная. Хорошо скомпилированный код будет хранить этот указатель в регистре процессора, а не перезагружать его каждый раз, когда он используется.
Да, конечно. Но это'ы балансирование.
Низкое приложений памяти обычно строится с учетом компромисса между верхними нескольких переменных указатель по сравнению с ВЛ, что бы программа massive (которые должны быть сохранены в памяти, помню!) если указатели не могут быть использованы.
Это относится к программам все, потому что никто не хочет строить ужасные, unmaintainable бардак с дублированным кодом налево и направо, что's в двадцать раз больше, чем он должен быть.
Имея указатель наверняка потребляет некоторые накладные расходы, но вы можете тоже посмотреть вверх.Указатель, как указатель. В C вы можете использовать сложные структуры данных, такие как строки и сооружений от указатели только. <БР><БР> В самом деле, предположим, что вы хотите передать параметр по ссылке, то его легко поддерживать указатель, а не копировать всю структуру и синхронизацию изменений между ними(даже копируя их, вам понадобится указатель ). Как бы вы справились с номера непрерывные выделения памяти и освобождает без указателя ?<БР><БР> Даже ваши обычные переменные имеют запись в таблице символов, которая хранит адрес переменной, указывающей в сторону. Так что, я не'т думаю, что это создает много накладных расходов с точки зрения памяти(только 4 или 8 байт) . Даже такие языки, как Java использовать указатели внутри(Ссылка), они просто не'т позволю тебе манипулировать ими так, как это сделает JVM не менее безопасной.<БР><БР> Вы должны использовать указатели только тогда, когда у вас нет другого выбора, как не хватает данных-типы, конструкции(в C) как с помощью указателей может привести к ошибкам при неправильном обращении и сравнительно труднее отлаживать.
В таких языках, как C и C++, при использовании указателей на переменные нам нужна одна больше памяти для сохранения этого адреса. Разве'т это в памяти?
Вы предполагаете, что указатель должен быть сохранен. Это не всегда так. Каждая переменная хранится в какой-то адрес в памяти. Скажем, у вас есть "длинные" объявлено длиной n = 5л;. Это выделяет память для " N " на какой-то адрес. Мы можем использовать этот адрес, чтобы делать необычные вещи, как
(к(char ) &Н) = (тип char) значение 0xFF;чтобы манипулировать частями
Н. Адрес
Н` Это'т хранится в качестве дополнительной нагрузки.
как это компенсируется?
Даже если указатели явно не храниться (например, в структурах данных, таких как списки), в результате структура данных часто более элегантно (проще, понятнее, проще в обращении и т. д.), чем эквивалентные структуры данных без указателей.
указатели используются во время критических применений низкого памяти?
Да. Устройства, которые используют часто микро-контроллеров содержат очень мало памяти, но прошивки могут использовать указатели для обработки векторов прерываний или управления буфером и т. д.
так это'т это память? Да.... нет... может быть? Это щекотливый вопрос, потому что, представьте себе диапазон адресации памяти компьютера, и программного обеспечения, который должен постоянно отслеживать, где все в памяти таким образом, что может'т быть привязан к стеку. Например, представьте себе музыкальный плеер, где звучит музыка, файл загружается на нажатие кнопки пользователем и выгружается из оперативной памяти, когда пользователь пытается загрузить другой музыкальный файл. Как мы можем отслеживать, где аудиоданные? Нам нужен адрес в памяти к нему. Программа не только должен следить за кусок аудио данных в памяти, но и где в памяти. Таким образом, мы должны держать около адрес памяти (т. е. указатель). И размера памяти, необходимого для хранения адреса в памяти будет соответствовать диапазон адресации устройства (например, 64-разрядный указатель на 64-битном диапазоне адресация). Так что'ы вроде "Да", он не требует хранения отслеживать адреса памяти, но это's не как мы можем избежать этого для динамически выделенной памяти такого рода. как это компенсируется? Про просто размер самого указателя, вы можете избежать издержек, в некоторых случаях за счет использования стека, например, в том случае, компиляторы могут генерировать инструкции, которые эффективно жестко относительный адрес в памяти, позволяет избежать затрат на указатель. Но это оставляет вас уязвимыми для переполнения стека, если вы делаете это для больших, переменного размера ассигнований, а также, как правило, нецелесообразно (если не сказать невозможно) сделать сложный комплекс отраслей обусловлен пользовательского ввода (как в аудио-примере выше). Другой способ заключается в использовании более последовательных структур данных. К примеру, массив на основе последовательностей может быть использован вместо двусвязный список, который требует двух указателей на узел. Мы также можем использовать гибрид этих двух как раскатали список, который хранит только указатели в между каждой непрерывной группы из n элементов. - указатели, используемые во время критических приложений памяти? Да, очень часто так, как много производительности критически важных приложений, написанных на C или C++, которые преобладают указатель использования (они могут быть за умного указателя или контейнером типа
СТД::вектор
илиСТД::строка
, но в основе механики сводятся к указателю, который используется для отслеживания обращения к динамической памяти). Теперь вернемся к этому вопросу: как это компенсируется? (Часть Вторая) Указатели обычно дешевы, если вы'вновь, как хранить миллион из них (который до сих пор жалкие 8 мегабайт на 64-разрядном компьютере). <суб> обратите внимание, как Бен отметил, что на "жалкие" с 8 мегов до сих пор размер кэш-памяти L3. Здесь я и"жалкие" больше в смысле общее использование памяти DRAM и типичный относительный размер блоков памяти, здоровый использование указателей будет указывать на.</суб> Где указатели дорого обойтись не сами указатели, но:
- Динамическое выделение памяти. Динамическое выделение памяти имеет тенденцию быть дорого, поскольку он должен пройти через базовую структуру данных (например: приятель или плиты распределителя). Хотя эти, как правило, оптимизированы до смерти, они'повторного общего назначения и предназначены для обработки с переменным размером блоков, которые требуют, чтобы они хоть немного работать, напоминающее "в поиск", которая (пусть и легкий и, возможно, даже постоянное время), чтобы найти свободный набор последовательных страниц в памяти.
- Доступа к памяти. Это, как правило, больше накладных расходов для беспокойства. Когда память выделяется динамически в первый раз, там'ы обязательный ошибка страницы, а также промахов кэша перенос памяти в иерархии памяти и в регистре. Доступ К Памяти Доступ к памяти является одним из наиболее важных аспектов производительности за алгоритмы. Много критических областях, как игровые движки ААА уделено много своей энергии в сторону ориентированных на данные оптимизации, которые сводятся к более эффективные способы доступа к памяти и макеты. Одна из самых больших трудностей исполнения высокоуровневых языков, которые хотите выделить для каждого пользовательского типа отдельно через сборщик мусора, например, в том, что они смогут фрагмент памяти совсем немного. Это может быть особенно верно, если не все объекты выделяются сразу. В тех случаях, если вы храните список в миллион экземпляров определяемого пользователем типа объекта, связи c тех случаях последовательно в цикле может быть довольно медленным, так как он'ы аналогично список миллиона указатели, которые указывают на разрозненных областей памяти. В тех случаях, архитектура хочет принести форму верхней памяти, медленнее, больше уровней иерархии в большие, выровненные блоки с надеждой, что окружающие данные в эти блоки будут доступны до выселения. Когда каждый объект в таком списке выделены отдельно, то часто мы в конечном итоге платить за это кэш-промахов при каждой последующей итерации, возможно, придется загрузить из совершенно другой области памяти без каких-либо соседних объектов осуществляется до выселения. Многие компиляторы для таких языков, делают очень большую работу в эти дни по поручению отбора и распределения регистров, но отсутствие более прямой контроль над памятью управления здесь может быть убийцей (хотя часто и с меньшим количеством ошибок) и до сих пор делают такие языки, как C и C++ довольно популярны. Косвенно Оптимизация Доступа К Указателю В самых критических сценариях, приложения часто используют пулов памяти, которая памяти из последовательных блоков, чтобы улучшить локальность ссылок. В таких случаях, даже связанную структуру, как дерево или список ссылок можно сделать кэш-фрэндли, при условии, что разметка памяти ее узлов являются непрерывными по своей природе. Это эффективно делать разыменование указателя дешевле, хотя и косвенно за счет повышения локальности ссылок, задействованных при разыменовании их. Гнать Указатели Вокруг Предположим, у нас есть поодиночке-связанный список, как:
Foo->Bar->Baz->null
Проблема в том, что если мы выделяем все эти узлы отдельно в отношении общего назначения распределитель (и, возможно, не все сразу), фактический объем памяти может быть разогнан вроде этой (упрощенная схема):
Когда мы начинаем гонять стрелки по периметру и открыть класса Foo
узел, мы начинаем с обязательного пропустить (и, возможно, ошибка страницы) перемещение фрагмента из своей области памяти и меньшим областям памяти, чтобы быстрее областях памяти, вроде так:
Это приводит нас к кэшу (возможно также страница) области памяти, только часть ее и выселить остальных, как мы погоним указатели вокруг этого списка. Взяв контроль над распределителем памяти, однако можно выделить такой список последовательно вот так:
... и тем самым значительно улучшить скорость, с которой мы можем разыменовать эти указатели и процесс их pointees. Так что, хоть и весьма косвенное, мы можем ускорить доступ к указатель на этот путь. Конечно, если бы мы просто положили рядом в массив, мы не'т иметь эту проблему на первое место, но распределитель памяти здесь дает нам явное управление памятью может спасти день, когда требуется связать структура.
<суб>* Примечание: это очень упрощенно схема и обсуждения об иерархии памяти и расположение ссылок, но, надеюсь, это's необходимости на уровне вопрос.</суб>
разве'т это память?
Это действительно память, но очень маленький (до ничтожности).
как это компенсируется?
Это не компенсируется. Вы должны понимать, что доступ к данным через указатель (разыменование указателя) очень быстро (если я правильно помню, он использует только одну инструкцию сборки за разыменования). Достаточно быстро, что это будет во многих случаях наиболее быстрый вариант у вас.
указатели используются во время критических применений низкого памяти?
Да.
Вам нужно только лишнее использование памяти (4-8 байт на указатель, как правило), а вам нужен этот указатель. Есть много методов, которые делают эту услугу более доступной.
Самая фундаментальная техника, которая делает мощные указки заключается в том, что вы Дон'т нужна, чтобы держать каждый указатель. Иногда вы можете использовать алгоритм для построения указатель от указателя на что-то другое. Наиболее тривиальным примером этого является арифметической. Если вы выделите массив из 50 целых чисел, вы Don'т нужна, чтобы держать 50 указателей, по одному на каждое число. Как правило, отслеживать один указатель (первый), и использовать арифметические операции над указателями, чтобы создать другим на лету. Иногда вы можете держать один из этих указателей на конкретный элемент массива временно, но только тогда, когда вам это нужно. Как только вы'вновь выполнена, вы можете отказаться от него, так долго, как вы сохранили достаточно информации, чтобы восстановить его позже, если вам это нужно. Это может показаться тривиальным, но именно этот вид сохранения средств вы'будете использовать, если вы действительно заботитесь о том, как много ссылок вы держите в памяти.
В крайне жесткой ситуации памяти, это может использоваться, чтобы минимизировать затраты. Если вы работаете в весьма ограниченное пространство памяти, вы, как правило, имеют хорошее представление о том, сколько объектов необходимо манипулировать. Вместо того, чтобы выделять кучу целых чисел, по одному за раз и сохраняя полный указатели на них, вы может воспользоваться ваш уровень знаний разработчика, которые вы'll никогда не превышает 256 целых чисел в данном конкретном алгоритме. В этом случае, вы можете сохранить указатель на целое, и отследить индекс, используя тип char (1 байт), а не через полный указатель (4/8 байт). Вы также можете использовать алгоритмические приемы для создания некоторых из этих показателей на лету.
Этот вид совестливость память была очень популярна в прошлом. Например, NES игры будет сильно зависеть от их способности зубрить данных и генерировать указатели алгоритмически вместо того, чтобы хранить их все оптом.
Экстремальных ситуациях памяти также может привести один, чтобы делать вещи, как распределение всех помещений, работы на во время компиляции. Затем указатель вы должны хранить в памяти, что хранится в программе, а не данные. Во многих случае нехватки памяти, у вас есть отдельные программы и памяти данных (ПЗУ против RAM), так что вы сможете настроить, как вы используете свой алгоритм, чтобы подтолкнуть указатели в памяти программы.
Принципиально, вы можете'т избавиться от всех накладных расходов. Однако, вы можете контролировать его. С помощью алгоритмических методов, вы можете минимизировать количество указателей можно хранить. Если вам случится быть с использованием указателей на динамическую память, вы'll никогда не будет ниже стоимости содержания 1 указатель на динамическую память место, потому что'с минимальным объемом информации, который необходим, чтобы открыть что-нибудь в этом блоке памяти. Однако в самые сжатые сценарии ограничения памяти, это обычно бывает особый случай (динамической памяти и ультра-жестких ограничений памяти, как правило, не появляются в одних и тех же ситуациях).
Во многих случаях указатели реально сэкономить память. Общий альтернативы с помощью указателей-сделать копию структуры данных. Полную копию структуры данных будет больше, чем указатель.
Одним из примеров критический момент приложение представляет собой сетевой стек. Хороший сетевой стек будет разработан, чтобы быть "копия& "на ноль" - и для этого требуется грамотное использование указателей.