Старые malloc()
Используемые системы UNIX sbrk()
/brk()
системные вызовы. Но в наши дни в реализациях используются mmap()
и sbrk()
. Реализация glibc malloc()
(это, вероятно, тот, который вы используете на вашем Ubuntu 14.04) использует как sbrk()
, так и mmap()
, и выбор того, какой из них выделять при запросе, обычно зависит от размера запроса на распределение, который glibc выполняет динамически.
Для небольших распределений glibc использует sbrk()
, а для больших распределений используется mmap()
. Для решения этого вопроса используется макрос M_MMAP_THRESHOLD
. В настоящее время значением по умолчанию является set to 128K. Это объясняет, почему вашему коду удалось выделить 135152 байта, поскольку это примерно ~ 128K. Несмотря на то, что вы запросили только 1 байт, ваша реализация выделяет 128 КБ для эффективного распределения памяти. Таким образом, segfault не произошел, пока вы не преодолеете этот предел.
Вы можете играть с M_MAP_THRESHOLD
с помощью mallopt()
, изменив параметры по умолчанию.
M_MMAP_THRESHOLD
Для распределения больше или равен пределу указанных (в байтах) по M_MMAP_THRESHOLD, которые не могут быть удовлетворены из свободного списка, функция памяти распределения использует ММАП (2) вместо этого увеличения разрыва программы с помощью sbrk (2).
Выделение памяти с помощью mmap (2) имеет существенное преимущество в том, что выделенные блоки памяти всегда могут независимо отбрасываться обратно в систему. (В отличие от этого куча может быть обрезана только в том случае, если память освобождена на верхнем конце.) С другой стороны, есть некоторые недостатки в использовании mmap (2): освобожденное пространство не размещено в свободном списке для повторного использования путем более поздних распределений; память может быть потрачена впустую , потому что mmap (2) распределения должны быть выровнены по страницам; и ядро должно выполнить дорогостоящую задачу обнуления памяти, выделенной через mmap (2). Балансировка этих факторов приводит к установке по умолчанию 128 * 1024 для параметра M_MMAP_THRESHOLD.
Нижний предел для этого параметра равно 0. Верхний предел DEFAULT_MMAP_THRESHOLD_MAX: 512 * 1024 на 32-разрядных системах или 4 * 1024 * 1024 * SizeOf (длинный) на 64-битных системах.
Примечание. В настоящее время glibc использует динамический порог mmap по умолчанию. Начальное значение порога составляет 128 * 1024, но когда блоки , превышающие текущий порог и меньше или равные , DEFAULT_MMAP_THRESHOLD_MAX освобождаются, пороговое значение корректируется вверх до размера освобожденного блока. Когда действует динамическое mmap , пороговое значение для обрезки кучи также равно , динамически скорректированное с удвоенным динамическим порогом mmap. Dynamic настройка порога mmap отключена, если задан какой-либо из параметров M_TRIM_THRESHOLD, M_TOP_PAD, M_MMAP_THRESHOLD или M_MMAP_MAX .
Например, если вы:
#include<malloc.h>
mallopt(M_MMAP_THRESHOLD, 0);
перед вызовом malloc()
, вы, вероятно, увидите другой предел. Большинство из них - детали реализации, а в стандарте C указано, что undefined behaviour записывает в память, что ваш процесс не принадлежит. Так что сделайте это на свой риск - в противном случае, demons may fly out of your nose ;-)
В какой операционной системе и архитектуре вы используете точно? Также вы уверены, что malloc() вызывает sbrk()? – Crashworks
Я не уверен, но мой профессор и некоторые онлайн-источники говорят мне об этом. Я использую архитектуру x86 под ubuntu 14.04 –
ITYM 4096, а не 4086. Что такое «(1)»? 'sbrk' - системный вызов (2), а' malloc' - это библиотечная функция (3). –