2015-09-23 4 views
0

чтение из книги, что, когда начинается процесс, его частный адрес пространство процесса создаетсяКак хранится «адресное пространство процесса Linux»?

Скажем, от 0x0 до 0xMAX

И одна часть пространства кучи, и мы написали для цикла для продолжения malloc (1k date), пока он не вернет false. Он назначил дату 3 ГБ.

Итак, вопрос, если 0x0 - 0xMAX выделяется в начале, значит, от 0x0 до 0xMAX больше 3 ГБ (так как есть стек, управление ...) с самого начала?

Если в начале процесс может занять более 3 ГБ, я должен понять, что это неправильно.

Может ли кто-нибудь объяснить, как этот 0x0 - 0xMAX хранится в попрошайничестве?

+1

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

+0

@MarcB Как и мой процесс, он может принять аргумент, чтобы создать кучу 3 ГБ или 3 МБ, которую компилятор едва ли может знать. Итак, в таком случае операционная система будет динамически обновлять всю память? поскольку куча от 0xXX продолжается до 0xMax, а стек - от 0xMax до нисходящего. его ОС хочет обновить его динамически, все пространство будет обновляться. – thundium

+0

@marcb, возможно, немного тангенциально, но есть некоторая копия-на-запись из родительского процесса, когда возникает вилка. –

ответ

1

Обычно загрузка исполняемого файла в память осуществляется процессом, выполняемым загрузчиком linux ld. Например, если я создаю очень простую программу, C позволяет сказать:

void main {} 

После компиляции этой программы с помощью GCC, мы получим исполняемый файл (ELF формат) a.out. Если проанализировать зависимости это очень простая программа есть, запустив LDD мы находим:

linux-gate.so.1 => (0x00545000) 
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00ccb000) 
/lib/ld-linux.so.2 (0x00594000) 

Первый linux-gate.so подвергается ядром, чтобы системные вызовы. ld-linux.so фактически является загрузчиком linux. Ответственность за загрузку любого исполняемого файла в память и его запуск. Если мы посмотрим на наш генерируемой a.out (с помощью HexEdit инструмента, например), мы можем видеть, что это заголовок содержит ссылку на то, где находится ЛД-Linux:

.ELF........................4...8....... 
4. ...(.........4...4...4... ... ....... 
........T...T...T....................... 
........................................ 
........................(...(...(....... 
................h...h...h...D...D....... 
....P.td............4...4...........Q.td 
............................R.td........ 
..................../lib/ld-linux.so.2.. 
............GNU......................... 
....GNU....F*QLk$,.....)..Yl............ 

После запуска процесса, ld-linux loader сначала проверяет, какие общие библиотеки вам нужны (зависит от них), и если они доступны или нет. В случае, если вы зависите от какой-либо общей библиотеки, недоступной ld-linux, не будет загружать этот процесс (ld-linux выглядит в вашей переменной env_LIBRARY_PATH, файле /etc/ld.so.cache и, наконец, по умолчанию:/lib и/usr/lib (man ld-linux для получения дополнительной информации).

Как только ld-linux заверяет, что все библиотеки есть, он выделяет память для загрузки процесса. Обычно исполняемый файл имеет несколько сегментов, для простоты мы могут сводить их к тексту (код), bss (неинициализированные данные), данные (инициализированные и статические данные). Когда процесс загружается в память, загрузчик резервирует объем памяти, необходимый для хранения всех этих разделов, и отображает в виртуальное пространство процесс всех разделяемых библиотек, от которых зависит процесс.Вы можете увидеть список карт определенного процесса в Linux консультируясь:

cat /proc/pid_of_process/maps 

Если я бег модифицированной версии простой программы выше (путем добавления вызова к USleep для того, чтобы получить ПИД-регулятор процесса) и проверить свои карты, мы получаем следующее (_ только, чтобы скрыть реальный путь, где появляется мой дом):

003a5000-003a6000 r-xp 00000000 00:00 0   [vdso] 
0075a000-008fd000 r-xp 00000000 08:03 2137894 /lib/i386-linux-gnu/libc-2.15.so 
008fd000-008ff000 r--p 001a3000 08:03 2137894 /lib/i386-linux-gnu/libc-2.15.so 
008ff000-00900000 rw-p 001a5000 08:03 2137894 /lib/i386-linux-gnu/libc-2.15.so 
00900000-00903000 rw-p 00000000 00:00 0 
00e4a000-00e6a000 r-xp 00000000 08:03 2137906 /lib/i386-linux-gnu/ld-2.15.so 
00e6a000-00e6b000 r--p 0001f000 08:03 2137906 /lib/i386-linux-gnu/ld-2.15.so 
00e6b000-00e6c000 rw-p 00020000 08:03 2137906 /lib/i386-linux-gnu/ld-2.15.so 
08048000-08049000 r-xp 00000000 08:05 3589145 /______________/test/a.out 
08049000-0804a000 r--p 00000000 08:05 3589145 /______________/test/a.out 
0804a000-0804b000 rw-p 00001000 08:05 3589145 /______________/test/a.out 
b771f000-b7720000 rw-p 00000000 00:00 0 
b7745000-b7747000 rw-p 00000000 00:00 0 
bf884000-bf8a5000 rw-p 00000000 00:00 0   [stack] 

Это на самом деле карта виртуальной памяти процесса. Эти страницы отображаются в физической памяти, и каждый процесс имеет свой собственный PMT (таблица программных карт), который используется для перевода между виртуальными и физическими адресами. В общем, память процесса имеет следующую структуру:

(от http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory/)

enter image description here

Так, с этой информацией в виду, и, возвращаясь к первоначальному вопросу,

So , вопрос, если в начале выделяется 0x0 до 0xMAX, значит, от 0x0 до 0xMAX больше 3 ГБ (поскольку есть стек, управление ...) с самого начала?

Ответ на этот вопрос не существует. Загрузчик резервирует необходимую физическую память для запуска процесса. После этого, в зависимости от потребностей процесса (динамического распределения памяти) и его поведения, его области кучи и стека могут расти и сокращаться. Каждый раз, когда процессу необходимо получить доступ к некоторой памяти (виртуальной), которая фактически не присутствует в физической памяти, выдается ошибка страницы, и эта страница загружается с диска в зарезервированное место в физической памяти. Несколько раз, чтобы сделать это, ядро ​​должно поменять какую-то страницу, принадлежащую другому процессу на диск. Физическая память - это ограниченный ресурс, который ОС должна обрабатывать правильно, чтобы обеспечить все запущенные процессы.

С помощью этой стратегии ядро ​​Linux может запускать несколько процессов, в которых каждый из них обычно имеет виртуальную память объемом 4 ГБ (32-битные системы) в физической памяти, меньшую, чем это (особенно в прошлом). В общем, даже если вы резервируете память динамически (используя malloc, например), вызов преуспевает, но на самом деле вы еще не резервируете эту физическую память. Ваш процесс получит его, как только он попытается использовать его (путем чтения или записи в эту память).

Возможно, это длинный ответ. Надеюсь, я не пропустил много деталей, и это поможет вам понять анатомию памяти процесса в Linux.

+0

Спасибо, я многому научился. –

0

Здесь есть некоторые недоразумения. Во-первых, существует разница между адресом процесса dpace и памятью, выделенной для процесса.

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

Если вы сделали malloc в цикле, вы вызываете (a), заставляя действительные страницы добавляться в процесс (b) вызывая выделение памяти служебной памяти в дополнение к возврату malloc.

В-третьих, в начале процесса есть таблицы страниц. (Игнорирование клонирования) Эти таблицы ничего не обозначают в начале процесса. Ваш процесс должен заставлять страницы выделяться и назначаться таблицам.

Смежные вопросы