Вопрос по поводу динамического распределения памяти - PullRequest
0 голосов
/ 03 августа 2010

У меня есть вопросы, касающиеся стеков и динамического распределения памяти.

1) Определяет ли ядро ​​размер стека динамически во время выполнения или устанавливает размер перед временем загрузки?Если размер стека выделяется динамически, как может произойти переполнение стека (потому что, если размер стека выходит за пределы, обработчик страницы выделит пространство для увеличения стека).Кроме того, если динамически распределяется, как может стек расти от более высокого адреса к более низкому адресу (потому что всегда виртуальный адрес увеличивается для динамически распределенного хранилища, верно?)

2) Также, если память выделяется динамически, используя malloc, размер области данныхрастет правильно?

Спасибо и С уважением,

Мышонок.

Ответы [ 3 ]

3 голосов
/ 03 августа 2010

1) Это отчасти зависит от ОС, но типичная схема заключается в том, что ОС предоставляет вам одну страницу виртуальной памяти (обычно это 4 КБ) для стека, а затем сразу после нее помечает страницу виртуальной памяти как«страница охраны».Это специальный флаг, который вызывает низкоуровневое исключение, которое запускается, когда приложение пытается записать в него.

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

После определенной точки (обычно 1 МБ) ОС прекратит это делать и вызовет исключение переполнения стека.Это просто потому, что они обычно указывают на программную ошибку, и код, который действительно нуждается в огромных стеках, может выделять память для любых данных их стека в куче.

2) Сегмент данных действительно "не растет"."Современные программы имеют фиксированное адресное пространство виртуальной памяти.malloc () использует некоторую схему, чтобы разделить это пространство и его части с реальной физической памятью.

Я думаю, что оба ваших вопроса намекают на желание лучшего понимания того, как ОС обеспечивает физическую память для ваших программ.Ключевым понятием в современных системах является виртуальная память. Страница Википедии о виртуальной памяти - хорошее место для начала.

Если вы хотите развить подробные знания, учебник по ОС был бы хорошим местом для начала.Предпочтительно тот, который лучше, чем у меня, когда я учился на курсе ОС в колледже:)

1 голос
/ 03 августа 2010

Размеры стека

Как правило, каждый поток имеет фиксированный стек при создании потока. Запустите ulimit -a, чтобы увидеть размер стека по умолчанию для вашей системы. В моей системе это 8 МБ. Когда вы создаете новые темы, вы можете давать им стеки меньшего или большего размера (см. pthread_attr_setstacksize).

Когда размер стека превысит 8 МБ, программа запишет в недопустимую область памяти и вылетит. Ядро следит за тем, чтобы все области памяти рядом со стеком были недействительными, чтобы обеспечить сбой программ при переполнении их стеков.

Вы можете подумать, что фиксированный размер является пустой тратой, но 8 МБ - это виртуальная память , а не физическая память . Разница важна, см. Ниже.

Malloc

В системах Unix распределение памяти имеет два уровня. Уровень пользовательского пространства равен malloccalloc, realloc, free). Это всего лишь часть библиотеки C, и ее можно заменить собственным кодом - это делает Firefox, и многие языки программирования используют свою собственную схему размещения, отличную от malloc. Различные реализации malloc являются кроссплатформенными.

Нижний уровень mmapsbrk). Функция mmap - это системный вызов, который изменяет адресное пространство вашей программы. Он может добавлять новые анонимные личные страницы в память вашей программы.

Цель malloc - получить большие куски виртуальной памяти из ядра, используя mmap (или sbrk), и эффективно разделить их для вашей программы. Системный вызов mmap работает только с кратностью 4 КиБ (в большинстве систем).

Память: виртуальная или реальная

Помните, что стек и вся память, возвращаемая mmap, - это просто виртуальная память, а не физическая память. Ядро не выделяет физическую оперативную память вашему процессу, пока вы ее не используете.

Когда вы получаете анонимную память от ядра, либо в куче, либо в стеке, она заполняется нулями. Однако вместо того, чтобы давать вам сотни страниц физической памяти, предварительно заполненной нулями, ядро ​​заставляет всю эту виртуальную память разделять одну страницу физической памяти. Виртуальная память помечена только для чтения. Как только вы пишете в него, процессор выдает исключение, передает ядру управление, и ядро ​​выделяет для вашей программы новую, обнуляемую страницу с нулевой записью.

Это объясняет, почему:

  • calloc быстрее, чем malloc + memset (потому что calloc знает, что страницы mmap 'предварительно обнулены, и memset вызывает выделение физической ОЗУ)
  • Вы можете выделить гораздо больше памяти, чем объединенный RAM + swap (потому что он не используется, пока вы не запишите в него)
0 голосов
/ 03 августа 2010

1) Динамическое выделение памяти происходит из кучи, а не из стека. Стек является блоком памяти для каждого потока, который также обрабатывает локальные переменные и адреса возврата во время вызовов функций. Куча представляет собой один или несколько блоков памяти, выделенных из ОС, которые C RTL подразделяет по мере необходимости для удовлетворения вызовов malloc.

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

2) Не обязательно. Пока текущего выделения памяти из ОС достаточно, malloc просто использует его. Если этого не произошло, это может привести к дополнительному выделению.

Я знаю, что вы хотите больше подробностей здесь, но я не уверен, что полезно. Я мог бы рассказать о том, как куча обычно реализуется в виде связанных списков свободных блоков с заголовками арены, которые определяют их размер, или о том, как некоторые системы используют блоки фиксированного размера для небольших выделений для ограничения фрагментации, или даже о том, как пузырьки памяти объединяются, когда нет единого достаточно большой блок найден. Однако все это детали реализации, которые могут оказаться неприменимыми в вашем случае, по крайней мере, не совсем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...