Это всё очень просто... для тех, кто понимает. ;)
Итак, общеизвестно, что адресное пространство задачи процесса состоИт из страниц; т.е. у каждого процесса есть таблица дескрипторов страниц, а элементы таблицы (дескрипторы) ссылаются на четырёхкилобайтные куски памяти (т.е. содержат адресА этих кусков). {Дискуссия о том, что у разных архитектур разный размер страницы, откладывается.} При этом никто не мешает нескольким дескрипторам (или разных таблиц) ссылаться на одну и ту же страницу.
Допустим, некий процесс делает fork(); будет ли при этом копироваться вся его память (и код, и данные)? Нет, т.к. есть лучший способ - у обоих процессов делаются одинаковые таблицы дескрипторов, но все данные помечаются как ReadOnly ("замораживаются"); если один из процессов модифицирует содержимое страницы, то только тогда создаётся копия этой страницы, таблицы обоих процессов модифицируются, модифицированная одним из процессов страница "размораживается" для обоих процессов. (Если fork() делался дважды и более, ситуёвина немного сложнее, но примерное представление я уже дал.)
Кстати, код у всех процессов, порождённых одним файлом, всегда общий - т.е. два юзера запустили /bin/csh, а код занимает место в памяти один таз (это порождает свои напряги - например, при сбросе и при подкачке кода надо модифицировать таблицы дескрипторов страниц для всех процессов).
Что-то меня занесло - надо вернуться к теме.
Итак, процесс делает alloc(...); по стандарту ему должны вернуть адрес куска памяти, заполненного нулями (случай "нет тебе у меня ресурсов!" не рассматриваем). А на фига выделять процессу память и заливать её нулями, когда можно взять одну страницу, изначально заполненную нулями, и все дескрипторы страниц, отвечающие за аллокированный кусок памяти (или точнее, адресного пространства), "заморозить" и направить на эту страницу (изначально заполненную нулями)? Когда надо будет (т.е. когда процесс захочеть записАть в одну из страниц данные), произойдёи exception, по которому ядро выделит процессу память, поменяет в таблице дескриптор этой страницы и вернёт управление процессу.
Интересное следствие: Процесс может делать alloc(сколь_угодно_много), отказа ему не будет даже в том случае, когда он просит больше, чем суммарный размер оперативки и свопа; зато память (и виртуальная тоже) может кончиться в совершенно произвольный момент (ну, не совсем произвольный, а в момент записи данных в аллокированную область).
Кстати, аналогично делается с файловой системой. Операции
open(новый_файл);
lseek(от_начала,куда_подальше);
write(один_байт);
создадут файл большого размера; но место на диске уменьшится весьма незначительно. И механизм тут тот же самый: все залитые нулями кластеры - это один общий для всех файлов кластер (ну, не для всех, а для тех, кому нужен такой кластер).
PS: Перечитал вопрос и понял, что м.б. ещё проще: процесс имеет нехилого размера экзешник и задействует тучу динамических библиотек. Часть кода находится в памяти, остальное просто в данный момент не нужно. Надеюсь, все тут в курсе, что при запуске программы и подключении динамических библиотек те файлы, в которых лежат код и данные программы и библиотек, присоединяются к свопу? Иными словами, имея 16 MB RAM + 20 MB Swap я запросто могу запустить стомегабайтную программу - лишь бы модифицируемые данные не превысили 36 MB (про память, занимаемую ядром, я забыл и вспоминать не хочу; это - самостоятельная работа на дом).
PPS: Если кто хочет, чтобы я это преподавал - обращайтесь в СтинсКоман http://www.infosystems.ru