Размеры стека
Как правило, каждый поток имеет фиксированный стек при создании потока. Запустите ulimit -a
, чтобы увидеть размер стека по умолчанию для вашей системы. В моей системе это 8 МБ. Когда вы создаете новые темы, вы можете давать им стеки меньшего или большего размера (см. pthread_attr_setstacksize
).
Когда размер стека превысит 8 МБ, программа запишет в недопустимую область памяти и вылетит. Ядро следит за тем, чтобы все области памяти рядом со стеком были недействительными, чтобы обеспечить сбой программ при переполнении их стеков.
Вы можете подумать, что фиксированный размер является пустой тратой, но 8 МБ - это виртуальная память , а не физическая память . Разница важна, см. Ниже.
Malloc
В системах Unix распределение памяти имеет два уровня. Уровень пользовательского пространства равен malloc
(и calloc
, realloc
, free
). Это всего лишь часть библиотеки C, и ее можно заменить собственным кодом - это делает Firefox, и многие языки программирования используют свою собственную схему размещения, отличную от malloc
. Различные реализации malloc
являются кроссплатформенными.
Нижний уровень mmap
(и sbrk
). Функция mmap
- это системный вызов, который изменяет адресное пространство вашей программы. Он может добавлять новые анонимные личные страницы в память вашей программы.
Цель malloc
- получить большие куски виртуальной памяти из ядра, используя mmap
(или sbrk
), и эффективно разделить их для вашей программы. Системный вызов mmap
работает только с кратностью 4 КиБ (в большинстве систем).
Память: виртуальная или реальная
Помните, что стек и вся память, возвращаемая mmap
, - это просто виртуальная память, а не физическая память. Ядро не выделяет физическую оперативную память вашему процессу, пока вы ее не используете.
Когда вы получаете анонимную память от ядра, либо в куче, либо в стеке, она заполняется нулями. Однако вместо того, чтобы давать вам сотни страниц физической памяти, предварительно заполненной нулями, ядро заставляет всю эту виртуальную память разделять одну страницу физической памяти. Виртуальная память помечена только для чтения. Как только вы пишете в него, процессор выдает исключение, передает ядру управление, и ядро выделяет для вашей программы новую, обнуляемую страницу с нулевой записью.
Это объясняет, почему:
calloc
быстрее, чем malloc
+ memset
(потому что calloc
знает, что страницы mmap
'предварительно обнулены, и memset
вызывает выделение физической ОЗУ)
- Вы можете выделить гораздо больше памяти, чем объединенный RAM + swap (потому что он не используется, пока вы не запишите в него)