Ответ 1
Прежде всего, единственный способ быть абсолютно уверенным в том, что происходит, - прочитать исходный код malloc
. Или даже лучше, перейдите к нему с помощью отладчика.
Но во всяком случае, вот мое понимание этих вещей:
- Системный вызов
sbrk()
используется для увеличения размера раздела данных, все в порядке. Обычно вы не будете называть его напрямую, но он будет вызван реализациейmalloc()
, чтобы увеличить память, доступную для кучи. - Функция
malloc()
не выделяет память из ОС. Он просто разбивает секцию данных на части и присваивает эти части тем, кто в них нуждается. Вы используетеfree()
для обозначения одной части как неиспользуемой и доступной для переназначения. - Точка 2 является упрощением. По крайней мере, реализация GCC для больших блоков
malloc()
выделяет их с помощьюmmap()
с частными, не файловыми файлами. Таким образом, эти блоки находятся вне сегмента данных. Очевидно, вызовfree()
в таком блоке вызоветmunmap()
.
Что такое большой блок, зависит от многих деталей. См. man mallopt
для подробностей.
Из этого вы можете догадаться, что происходит, когда вы получаете доступ к свободной памяти:
- Если блок был небольшим, память все равно будет там, поэтому, если вы ничего не прочитаете, это произойдет. Если вы напишете на него, вы можете повредить внутренние структуры кучи или, возможно, были повторно использованы, и вы можете повредить любую случайную структуру.
- Если блок был большой, память не была отображена, поэтому любой доступ приведет к ошибке сегментации. Если невероятная ситуация, в которой промежуточный, выделяется другой большой блок (или другой поток вызывает
mmap()
, и используется тот же диапазон адресов.
Разъяснение
Раздел данных терминов используется с двумя разными значениями, в зависимости от контекста.
- Раздел
.data
исполняемого файла (линкерная точка зрения). Он может также включать.bss
или даже.rdata
. Для ОС это ничего не значит, оно просто отображает фрагменты программы в память, не заботясь о том, что она содержит, кроме флагов (только для чтения, исполняемый файл...). - Куча, этот блок памяти, который есть у каждого процесса, который не читается из исполняемого файла, и который можно вырастить с помощью
sbrk()
.
Вы можете видеть, что с помощью следующей команды, которая печатает макет памяти простой программы (cat
):
$ cat /proc/self/maps
08048000-08053000 r-xp 00000000 00:0f 1821106 /usr/bin/cat
08053000-08054000 r--p 0000a000 00:0f 1821106 /usr/bin/cat
08054000-08055000 rw-p 0000b000 00:0f 1821106 /usr/bin/cat
09152000-09173000 rw-p 00000000 00:00 0 [heap]
b73df000-b75a5000 r--p 00000000 00:0f 2241249 /usr/lib/locale/locale-archive
b75a5000-b75a6000 rw-p 00000000 00:00 0
b75a6000-b774f000 r-xp 00000000 00:0f 2240939 /usr/lib/libc-2.18.so
b774f000-b7750000 ---p 001a9000 00:0f 2240939 /usr/lib/libc-2.18.so
b7750000-b7752000 r--p 001a9000 00:0f 2240939 /usr/lib/libc-2.18.so
b7752000-b7753000 rw-p 001ab000 00:0f 2240939 /usr/lib/libc-2.18.so
b7753000-b7756000 rw-p 00000000 00:00 0
b7781000-b7782000 rw-p 00000000 00:00 0
b7782000-b7783000 r-xp 00000000 00:00 0 [vdso]
b7783000-b77a3000 r-xp 00000000 00:0f 2240927 /usr/lib/ld-2.18.so
b77a3000-b77a4000 r--p 0001f000 00:0f 2240927 /usr/lib/ld-2.18.so
b77a4000-b77a5000 rw-p 00020000 00:0f 2240927 /usr/lib/ld-2.18.so
bfba0000-bfbc1000 rw-p 00000000 00:00 0 [stack]
Первая строка - это исполняемый код (раздел .text
).
Вторая строка - это данные только для чтения (.rdata
) и некоторые другие разделы только для чтения.
Третья строка - это .data
+ .bss
и некоторые другие записываемые разделы.
Четвертая строка - куча!
Следующие строки, те, у которых есть имя, являются файлами с отображением памяти или общими объектами. Те, у кого нет имени, вероятно, большие блоки памяти malloc'ed (или, возможно, частные анонимные mmap, их невозможно отличить).
Последняя строка - это стек!