Реализация вашего собственного malloc / free с помощью mmap и munmap - PullRequest
8 голосов
/ 12 декабря 2011

Я реализовал собственные malloc и free с использованием mmap . Теперь, в отличие от free , munmap также принимает длину в качестве параметра, поэтому я помещаю длину в качестве дополнительной информации в отображенную память.

Код для моих malloc и free показан ниже. Я хочу спросить, хорош ли этот код, или я все еще что-то упускаю или что-то делаю неправильно.

void * malloc ( size_t size )
{
    int *plen;
    int len = size + sizeof( size ); // Add sizeof( size ) for holding length.

    plen = mmap( 0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );

    *plen = len;                     // First 4 bytes contain length.
    return (void*)(&plen[1]);        // Memory that is after length variable.
}

void free ( void * ptr )
{
    int *plen = (int*)ptr;
    int len;

    plen--;                          // Reach top of memory
    len = *plen;                     // Read length

    munmap( (void*)plen, len );
}

Ответы [ 5 ]

14 голосов
/ 12 декабря 2011

Некоторые наблюдения:

  • Вы предполагаете, что int и size_t имеют одинаковый размер. Если вы хотите сохранить значение size_t в начале выделения, то почему бы вам просто не сделать это? Зачем вводить int?
  • Скорее всего, это будет весьма неэффективно, как с точки зрения использования памяти, так и скорости. mmap() имеет значительные накладные расходы, и обычно распределение не может быть меньше, чем "страница". Большинство реальных распределителей стараются по-разному избегать вызова функциональности уровня ОС для каждого malloc().
  • Если mmap() не удастся, он вернет MAP_FAILED, и так же должно быть malloc(). Таким образом, вам нужно проверить это перед разыменованием указателя, возвращенного mmap().
  • Вызов free(NULL) должен быть действительным; в вашей реализации это, скорее всего, вызовет сбой, поскольку вы не NULL проверяете аргумент, прежде чем предположить, что он действителен.
7 голосов
/ 12 декабря 2011

Вы должны, по крайней мере.

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

Для реализации malloc я также ожидал бы, что она по крайней мере будет иметь элементарную поддержку отладки, например, попытаться обнаружить двойные освобождения, попытаться обнаружить свободные недействительные указатели, список памяти не свободен и т. Д.

Имейте в виду, что ваша реализация malloc здесь может быть чрезвычайно расточительной. Если вы malloc 10 байтов, вы в конечном итоге выделите 1 страницу (4096 байт), которые должны быть сопоставлены с физической памятью, а остальные4082 байта не используются.

2 голосов
/ 12 декабря 2011

Читайте также c malloc в Википедии и внимательно изучите некоторые реальные реализации malloc, такие как malloc Дуга Ли .На эту тему много литературы, например, от Вольфрама Глогера и многих других.

@ MetallicPriest: вам действительно нужно гораздо больше объяснять, что вы делаете (я не оченьс оптимизмом смотрят на вашу работу, но вы, вероятно, многому научитесь!)

1 голос
/ 11 июня 2018

И вы также должны использовать -1 вместо 0 в качестве аргумента fd mmap.

mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)

MAP_ANONYMOUS

Отображение не поддерживается никаким файлом;его содержимое инициализируется до нуля.Аргументы fd и offset игнорируются;однако некоторые реализации требуют, чтобы fd было равно -1, если указано MAP_ANONYMOUS (или MAP_ANON), и переносимые приложения должны это гарантировать.Использование MAP_ANONYMOUS в сочетании с MAP_SHARED поддерживается только в Linux начиная с ядра 2.4.

1 голос
/ 12 декабря 2011

Вы не должны вызывать mmap каждый раз, когда вызываете свой пользовательский malloc. Как указывалось ранее, это приводит к огромным накладным расходам.

Вы должны создать разделяемую память большого размера (например, 4 КБ), и ваша функция malloc должна будет возвращать только указатели в диапазоне выделенной памяти.

Затем, если вам не хватает памяти, вы создаете еще 4 КБ общей памяти.

Вам просто нужно посчитать, сколько места вы используете, и отследить ваши ссылки, и таким образом освободить память намного проще.

...