Связь с процессором и памятью - PullRequest
3 голосов
/ 18 марта 2012

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

При кодировании базовой вещи (в C):

int myNumber;
myNumber = 3;
printf("Here's my number: %d", myNumber);

Я обнаружил, что (в основном на 32-битном процессоре) целое число занимает 32 бита = 4 байта. Итак, в первой строке моего кода процессор уходит в память. Память адресуема байтами, поэтому CPU выбирает для моей переменной 4 непрерывных байта и сохраняет адрес в первом (или последнем) байте.

Во второй строке моего кода CPU использует свой сохраненный адрес переменной MyNumber, переходит по этому адресу в памяти и находит там 32 бита зарезервированного пространства. Теперь его задача - хранить там число «3», поэтому он заполняет эти четыре байта последовательностью 00000000-00000000-00000000-00000011. В третьей строке он делает то же самое - процессор переходит на этот адрес в памяти и загружает число, сохраненное в этом адресе.

(Первый вопрос - правильно ли я понимаю?)

Что я не понимаю, так это:
Размер этого адреса (указатель на эту переменную) составляет 4 байта в 32-битном процессоре. (Вот почему 32-разрядный ЦП может использовать максимум 4 ГБ памяти - поскольку существует только 2 ^ 32 различных адреса двоичной длины 32)
Теперь, где процессор хранит эти адреса? Есть ли у него какая-то собственная память или кеш для хранения этого? И почему он хранит 32-битный адрес в 32-битном целом числе? Не лучше ли просто сохранить в своем кэше это действительное число, чем указатель на него при одинаковых размерах?

И последнее - если он хранит где-то в своем собственном кэше адреса всех этих целых чисел и длины одинаковы (4 байта), ему потребуется точно такое же пространство для хранения адресов, что и для фактических переменных. Но переменные могут занимать до 4 ГБ пространства, поэтому ЦП должен иметь 4 ГБ своего собственного пространства для хранения адресов этих переменных. И это звучит странно ..

Спасибо за помощь!
Я пытаюсь это понять, но это так сложно ..: - [

Ответы [ 4 ]

5 голосов
/ 18 марта 2012

(Первый вопрос - правильно ли я понимаю?)

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

Память является адресуемой по байту, поэтому CPU выбирает для моей переменной 4 непрерывных байта и сохраняет адрес в первом (или последнем) байте.

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

Размер этого адреса (указатель на эту переменную) составляет 4 байта в 32-битном процессоре. (Вот почему 32-разрядный процессор может использовать максимум 4 ГБ памяти - потому что существует только 2 ^ 32 разных адресов двоичной длины 32)

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

Теперь, где процессор хранит эти адреса?

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

В случае динамически распределяемых объектов (то есть вещи, которые были malloc -ed), программист обычно поддерживает соответствующую переменную указателя (в противном случае произошла бы утечка памяти!). Этот указатель также может быть динамически размещен (в случае сложной структуры данных), но если вы вернетесь достаточно далеко, вы в конечном итоге достигнете чего-то, что является локальной переменной. В этом случае применяется вышеуказанное правило.

Но переменные могут занимать до 4 ГБ пространства, поэтому ЦП должен иметь 4 ГБ своего собственного пространства для хранения адресов этих переменных.

Если ваша программа состоит из независимо malloc -миллионов int с, тогда да, вы получите столько же памяти, сколько требуется указателям. Но большинство программ не выглядят так. Обычно вы выделяете гораздо большие объекты (например, массив или большую структуру).

кэш

Особенности , где хранится , зависят от архитектуры. На современном x86 обычно имеется 2 или 3 слоя кеша между процессором и основной памятью. Но кеш не адресуется независимо; ЦП не может решить хранить int в кеше вместо основной памяти. Скорее, кеш - это фактически избыточная копия подмножества основной памяти.

Еще одна вещь, которую следует учитывать, - это то, что компилятор обычно имеет дело с виртуальными адресами при выделении хранилища для объектов. На современном x86 они сопоставляются с физическими адресами (то есть адресами, которые соответствуют байтам физической памяти в основной памяти) с помощью выделенного оборудования вместе с поддержкой ОС.


1. Кроме того, компилятор может полностью оптимизировать его.
3 голосов
/ 18 марта 2012

Во второй строке моего кода CPU использует свой сохраненный адрес переменной MyNumber, переходит по этому адресу в памяти и находит там 32 бита зарезервированного пространства.

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

Теперь, где процессор хранит эти адреса?У него есть какая-то собственная память или кеш для хранения этого?И почему он хранит 32-битный адрес в 32-битное целое число?Не лучше ли просто сохранить в своем кеше это действительное число, а не указатель на него при одинаковых размерах?

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

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

0 голосов
/ 18 марта 2012

Внутри ЦП есть один регистр, который содержит адрес следующей команды, которая должна быть выполнена.Сами инструкции хранят информацию о том, где находится переменная.Если переменная оптимизирована, инструкция может указывать на регистр, но в общем случае инструкция будет иметь адрес доступной переменной.Ваш код, после компиляции и загрузки в память, содержит все это!Я рекомендую изучить ассемблер, чтобы лучше понять все это.Удачи!

0 голосов
/ 18 марта 2012

И также имейте в виду, что адреса, которые видит ваша программа, могут не быть (или, скорее, редко) физическими адресами, начиная с «начала памяти» или 0. В основном это смещения в конкретном блоке памяти, где менеджер памятизнает реальный адрес и доступ через base + offest как реальное хранилище данных.

И нам действительно нужна память, поскольку кэши ограничены; -)

Mario

...